@onesub/server 0.14.0 → 0.16.0

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 (140) hide show
  1. package/dist/__tests__/google-subscriptions-v2.test.d.ts +1 -1
  2. package/dist/__tests__/receipt-age.test.d.ts +7 -0
  3. package/dist/__tests__/receipt-age.test.d.ts.map +1 -0
  4. package/dist/__tests__/tracing.test.d.ts +2 -0
  5. package/dist/__tests__/tracing.test.d.ts.map +1 -0
  6. package/dist/cache.d.ts +5 -0
  7. package/dist/cache.d.ts.map +1 -1
  8. package/dist/index.cjs +178 -55
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.js +178 -55
  11. package/dist/index.js.map +1 -1
  12. package/dist/providers/apple.d.ts.map +1 -1
  13. package/dist/providers/google.d.ts.map +1 -1
  14. package/dist/providers/mock.d.ts.map +1 -1
  15. package/dist/routes/admin.d.ts.map +1 -1
  16. package/dist/routes/purchase.d.ts.map +1 -1
  17. package/dist/routes/validate.d.ts.map +1 -1
  18. package/dist/routes/webhook-apple.d.ts.map +1 -1
  19. package/dist/routes/webhook-google.d.ts +1 -1
  20. package/dist/routes/webhook-google.d.ts.map +1 -1
  21. package/dist/store.d.ts.map +1 -1
  22. package/dist/stores/postgres.d.ts.map +1 -1
  23. package/dist/stores/redis.d.ts +1 -0
  24. package/dist/stores/redis.d.ts.map +1 -1
  25. package/dist/tracing.d.ts.map +1 -1
  26. package/dist/webhook-events.d.ts +10 -0
  27. package/dist/webhook-events.d.ts.map +1 -1
  28. package/package.json +5 -3
  29. package/dist/__tests__/admin-customer-detail.test.js +0 -146
  30. package/dist/__tests__/admin-customer-detail.test.js.map +0 -1
  31. package/dist/__tests__/admin-list-subscriptions.test.js +0 -192
  32. package/dist/__tests__/admin-list-subscriptions.test.js.map +0 -1
  33. package/dist/__tests__/admin-subscription-detail.test.js +0 -112
  34. package/dist/__tests__/admin-subscription-detail.test.js.map +0 -1
  35. package/dist/__tests__/apple-root-ca.test.js +0 -41
  36. package/dist/__tests__/apple-root-ca.test.js.map +0 -1
  37. package/dist/__tests__/apple-status-api.test.js +0 -345
  38. package/dist/__tests__/apple-status-api.test.js.map +0 -1
  39. package/dist/__tests__/cache.test.js +0 -34
  40. package/dist/__tests__/cache.test.js.map +0 -1
  41. package/dist/__tests__/entitlements.test.js +0 -268
  42. package/dist/__tests__/entitlements.test.js.map +0 -1
  43. package/dist/__tests__/error-codes.test.js +0 -173
  44. package/dist/__tests__/error-codes.test.js.map +0 -1
  45. package/dist/__tests__/fetch-hardening.test.js +0 -192
  46. package/dist/__tests__/fetch-hardening.test.js.map +0 -1
  47. package/dist/__tests__/google-paused.test.js +0 -126
  48. package/dist/__tests__/google-paused.test.js.map +0 -1
  49. package/dist/__tests__/google-price-change.test.js +0 -186
  50. package/dist/__tests__/google-price-change.test.js.map +0 -1
  51. package/dist/__tests__/google-subscriptions-v2.test.js +0 -206
  52. package/dist/__tests__/google-subscriptions-v2.test.js.map +0 -1
  53. package/dist/__tests__/lifecycle-scenarios.test.js +0 -579
  54. package/dist/__tests__/lifecycle-scenarios.test.js.map +0 -1
  55. package/dist/__tests__/lifecycle-states.test.js +0 -423
  56. package/dist/__tests__/lifecycle-states.test.js.map +0 -1
  57. package/dist/__tests__/linked-purchase-token.test.js +0 -227
  58. package/dist/__tests__/linked-purchase-token.test.js.map +0 -1
  59. package/dist/__tests__/metrics.test.js +0 -340
  60. package/dist/__tests__/metrics.test.js.map +0 -1
  61. package/dist/__tests__/mock-provider.test.js +0 -188
  62. package/dist/__tests__/mock-provider.test.js.map +0 -1
  63. package/dist/__tests__/openapi.test.js +0 -32
  64. package/dist/__tests__/openapi.test.js.map +0 -1
  65. package/dist/__tests__/paused-auto-resume.test.js +0 -162
  66. package/dist/__tests__/paused-auto-resume.test.js.map +0 -1
  67. package/dist/__tests__/providers.test.js +0 -321
  68. package/dist/__tests__/providers.test.js.map +0 -1
  69. package/dist/__tests__/redis-store.test.js +0 -166
  70. package/dist/__tests__/redis-store.test.js.map +0 -1
  71. package/dist/__tests__/refund-policy.test.js +0 -317
  72. package/dist/__tests__/refund-policy.test.js.map +0 -1
  73. package/dist/__tests__/schema.test.js +0 -46
  74. package/dist/__tests__/schema.test.js.map +0 -1
  75. package/dist/__tests__/store.test.js +0 -172
  76. package/dist/__tests__/store.test.js.map +0 -1
  77. package/dist/__tests__/test-utils.js +0 -30
  78. package/dist/__tests__/test-utils.js.map +0 -1
  79. package/dist/__tests__/webhook-apple.test.js +0 -247
  80. package/dist/__tests__/webhook-apple.test.js.map +0 -1
  81. package/dist/__tests__/webhook-events.test.js +0 -36
  82. package/dist/__tests__/webhook-events.test.js.map +0 -1
  83. package/dist/__tests__/webhook-google.test.js +0 -255
  84. package/dist/__tests__/webhook-google.test.js.map +0 -1
  85. package/dist/__tests__/webhook-queue.test.js +0 -26
  86. package/dist/__tests__/webhook-queue.test.js.map +0 -1
  87. package/dist/__tests__/webhook-refund.test.js +0 -313
  88. package/dist/__tests__/webhook-refund.test.js.map +0 -1
  89. package/dist/cache.js +0 -39
  90. package/dist/cache.js.map +0 -1
  91. package/dist/errors.js +0 -19
  92. package/dist/errors.js.map +0 -1
  93. package/dist/http.js +0 -36
  94. package/dist/http.js.map +0 -1
  95. package/dist/logger.js +0 -20
  96. package/dist/logger.js.map +0 -1
  97. package/dist/openapi.js +0 -196
  98. package/dist/openapi.js.map +0 -1
  99. package/dist/providers/apple-root-ca.js +0 -38
  100. package/dist/providers/apple-root-ca.js.map +0 -1
  101. package/dist/providers/apple.js +0 -630
  102. package/dist/providers/apple.js.map +0 -1
  103. package/dist/providers/google.js +0 -564
  104. package/dist/providers/google.js.map +0 -1
  105. package/dist/providers/mock.js +0 -93
  106. package/dist/providers/mock.js.map +0 -1
  107. package/dist/routes/admin.js +0 -327
  108. package/dist/routes/admin.js.map +0 -1
  109. package/dist/routes/apple-offer.js +0 -72
  110. package/dist/routes/apple-offer.js.map +0 -1
  111. package/dist/routes/entitlements.js +0 -130
  112. package/dist/routes/entitlements.js.map +0 -1
  113. package/dist/routes/metrics.js +0 -281
  114. package/dist/routes/metrics.js.map +0 -1
  115. package/dist/routes/purchase.js +0 -204
  116. package/dist/routes/purchase.js.map +0 -1
  117. package/dist/routes/status.js +0 -55
  118. package/dist/routes/status.js.map +0 -1
  119. package/dist/routes/validate.js +0 -70
  120. package/dist/routes/validate.js.map +0 -1
  121. package/dist/routes/webhook-apple.js +0 -145
  122. package/dist/routes/webhook-apple.js.map +0 -1
  123. package/dist/routes/webhook-google.js +0 -204
  124. package/dist/routes/webhook-google.js.map +0 -1
  125. package/dist/routes/webhook.js +0 -19
  126. package/dist/routes/webhook.js.map +0 -1
  127. package/dist/store.js +0 -145
  128. package/dist/store.js.map +0 -1
  129. package/dist/stores/postgres.js +0 -329
  130. package/dist/stores/postgres.js.map +0 -1
  131. package/dist/stores/redis.js +0 -297
  132. package/dist/stores/redis.js.map +0 -1
  133. package/dist/stores/schema.js +0 -67
  134. package/dist/stores/schema.js.map +0 -1
  135. package/dist/tracing.js +0 -74
  136. package/dist/tracing.js.map +0 -1
  137. package/dist/webhook-events.js +0 -58
  138. package/dist/webhook-events.js.map +0 -1
  139. package/dist/webhook-queue.js +0 -108
  140. package/dist/webhook-queue.js.map +0 -1
@@ -1,579 +0,0 @@
1
- /**
2
- * End-to-end lifecycle scenarios — exercise multi-notification sequences against
3
- * the real webhook router + status route + stores, the way Apple/Google would
4
- * deliver them in production.
5
- *
6
- * Single-notification correctness is covered by the per-feature unit tests; this
7
- * file catches issues that only show up when notifications arrive in a sequence:
8
- * stale state bleeding across transitions, idempotency under replay, recovery
9
- * paths after a missed webhook, etc.
10
- *
11
- * Why scenarios instead of more unit tests:
12
- * - The webhook handler has many branches (per-notification mapping, fresh
13
- * re-fetch, refundPolicy gating, hooks). Each is unit-tested in isolation,
14
- * but a transition like SUBSCRIBED → DID_FAIL_TO_RENEW(GRACE) → DID_RENEW
15
- * touches three of those branches in turn — a regression in any one only
16
- * surfaces when run together.
17
- * - These scenarios mirror the runbook for sandbox verification, so the
18
- * mock results here can be cross-checked against real sandbox behaviour.
19
- */
20
- import { describe, it, expect, beforeAll, beforeEach, vi } from 'vitest';
21
- import express from 'express';
22
- import { generateKeyPairSync } from 'crypto';
23
- import { SUBSCRIPTION_STATUS } from '@onesub/shared';
24
- import { createWebhookRouter } from '../routes/webhook.js';
25
- import { createStatusRouter } from '../routes/status.js';
26
- import { InMemorySubscriptionStore, InMemoryPurchaseStore } from '../store.js';
27
- import { __testing as appleTesting } from '../providers/apple.js';
28
- import { isLocalhostUrl, urlHost } from './test-utils.js';
29
- // ── helpers ─────────────────────────────────────────────────────────────────
30
- let testEcKey;
31
- let testRsaKey;
32
- beforeAll(() => {
33
- const ec = generateKeyPairSync('ec', { namedCurve: 'P-256' });
34
- testEcKey = ec.privateKey.export({ type: 'pkcs8', format: 'pem' });
35
- const rsa = generateKeyPairSync('rsa', { modulusLength: 2048 });
36
- testRsaKey = rsa.privateKey.export({ type: 'pkcs8', format: 'pem' });
37
- });
38
- beforeEach(() => {
39
- vi.restoreAllMocks();
40
- appleTesting.clearAppleJwtCacheForTests();
41
- });
42
- function makeJws(payload) {
43
- const header = Buffer.from(JSON.stringify({ alg: 'ES256' })).toString('base64url');
44
- const body = Buffer.from(JSON.stringify(payload)).toString('base64url');
45
- return `${header}.${body}.fakesig`;
46
- }
47
- function applePayload(notificationType, opts) {
48
- const signedTransactionInfo = makeJws({
49
- bundleId: 'com.example.app',
50
- type: opts.type ?? 'Auto-Renewable Subscription',
51
- productId: opts.productId ?? 'pro_monthly',
52
- transactionId: opts.transactionId ?? `tx_${opts.originalTransactionId}_${Date.now()}`,
53
- originalTransactionId: opts.originalTransactionId,
54
- purchaseDate: Date.now() - 30 * 86400000,
55
- expiresDate: opts.expiresDate ?? Date.now() + 30 * 86400000,
56
- environment: opts.environment ?? 'Production',
57
- });
58
- const signedRenewalInfo = makeJws({ autoRenewStatus: opts.autoRenewStatus ?? 1 });
59
- const payload = {
60
- notificationType,
61
- data: { signedTransactionInfo, signedRenewalInfo },
62
- };
63
- if (opts.subtype)
64
- payload.subtype = opts.subtype;
65
- return { signedPayload: makeJws(payload) };
66
- }
67
- function googlePush(notificationType, purchaseToken, subscriptionId = 'pro_monthly') {
68
- const json = JSON.stringify({
69
- version: '1.0',
70
- packageName: 'com.example.app',
71
- eventTimeMillis: String(Date.now()),
72
- subscriptionNotification: {
73
- version: '1.0',
74
- notificationType,
75
- purchaseToken,
76
- subscriptionId,
77
- },
78
- });
79
- return {
80
- message: { data: Buffer.from(json).toString('base64'), messageId: '1' },
81
- subscription: 's',
82
- };
83
- }
84
- function buildServers(config) {
85
- const store = new InMemorySubscriptionStore();
86
- const purchaseStore = new InMemoryPurchaseStore();
87
- const webhookApp = express();
88
- webhookApp.use(express.json());
89
- webhookApp.use(createWebhookRouter(config, store, purchaseStore));
90
- const statusApp = express();
91
- statusApp.use(express.json());
92
- statusApp.use(createStatusRouter(store));
93
- const post = async (app, path, body) => {
94
- const httpServer = app.listen(0);
95
- const port = httpServer.address().port;
96
- try {
97
- const resp = await fetch(`http://127.0.0.1:${port}${path}`, {
98
- method: 'POST',
99
- headers: { 'Content-Type': 'application/json' },
100
- body: JSON.stringify(body),
101
- });
102
- return { status: resp.status };
103
- }
104
- finally {
105
- await new Promise((r) => httpServer.close(() => r()));
106
- }
107
- };
108
- const get = async (app, path) => {
109
- const httpServer = app.listen(0);
110
- const port = httpServer.address().port;
111
- try {
112
- const resp = await fetch(`http://127.0.0.1:${port}${path}`);
113
- return (await resp.json());
114
- }
115
- finally {
116
- await new Promise((r) => httpServer.close(() => r()));
117
- }
118
- };
119
- return {
120
- store,
121
- purchaseStore,
122
- server: {
123
- webhook: (path, body) => post(webhookApp, path, body),
124
- status: (userId) => get(statusApp, `/onesub/status?userId=${encodeURIComponent(userId)}`),
125
- },
126
- };
127
- }
128
- const futureExpiry = '2099-01-01T00:00:00.000Z';
129
- const sampleSub = (overrides) => ({
130
- userId: 'real_user',
131
- productId: 'pro_monthly',
132
- platform: 'apple',
133
- status: 'active',
134
- expiresAt: futureExpiry,
135
- originalTransactionId: 'orig_x',
136
- purchasedAt: '2026-01-01T00:00:00.000Z',
137
- willRenew: true,
138
- ...overrides,
139
- });
140
- // ─────────────────────────────────────────────────────────────────────────────
141
- // Scenario 1 — Apple billing retry lifecycle
142
- // SUBSCRIBED → DID_FAIL_TO_RENEW(GRACE_PERIOD) → GRACE_PERIOD_EXPIRED → DID_RENEW
143
- // Verifies: each transition lands in the right status; entitlement (status route
144
- // active flag) flips on/off in lockstep; recovery to active works after on_hold.
145
- // ─────────────────────────────────────────────────────────────────────────────
146
- describe('Scenario 1 — Apple billing retry lifecycle', () => {
147
- it('SUBSCRIBED → grace_period → on_hold → active recovery', async () => {
148
- const config = {
149
- apple: { bundleId: 'com.example.app', skipJwsVerification: true },
150
- database: { url: '' },
151
- };
152
- const { store, server } = buildServers(config);
153
- const orig = 'orig_billing_retry';
154
- await store.save(sampleSub({ originalTransactionId: orig, userId: 'u_br' }));
155
- // 1. SUBSCRIBED — entitlement active
156
- await server.webhook('/onesub/webhook/apple', applePayload('SUBSCRIBED', {
157
- originalTransactionId: orig,
158
- expiresDate: Date.now() + 30 * 86400000,
159
- }));
160
- expect((await store.getByTransactionId(orig))?.status).toBe(SUBSCRIPTION_STATUS.ACTIVE);
161
- expect((await server.status('u_br')).active).toBe(true);
162
- // 2. DID_FAIL_TO_RENEW + GRACE_PERIOD subtype — entitlement still valid (grace)
163
- await server.webhook('/onesub/webhook/apple', applePayload('DID_FAIL_TO_RENEW', {
164
- originalTransactionId: orig,
165
- subtype: 'GRACE_PERIOD',
166
- }));
167
- expect((await store.getByTransactionId(orig))?.status).toBe(SUBSCRIPTION_STATUS.GRACE_PERIOD);
168
- expect((await server.status('u_br')).active).toBe(true); // grace counts as active
169
- // 3. GRACE_PERIOD_EXPIRED — billing retry, entitlement REVOKED
170
- await server.webhook('/onesub/webhook/apple', applePayload('GRACE_PERIOD_EXPIRED', {
171
- originalTransactionId: orig,
172
- }));
173
- expect((await store.getByTransactionId(orig))?.status).toBe(SUBSCRIPTION_STATUS.ON_HOLD);
174
- expect((await server.status('u_br')).active).toBe(false);
175
- // 4. DID_RENEW — recovery
176
- await server.webhook('/onesub/webhook/apple', applePayload('DID_RENEW', {
177
- originalTransactionId: orig,
178
- expiresDate: Date.now() + 60 * 86400000,
179
- }));
180
- expect((await store.getByTransactionId(orig))?.status).toBe(SUBSCRIPTION_STATUS.ACTIVE);
181
- expect((await server.status('u_br')).active).toBe(true);
182
- });
183
- });
184
- // ─────────────────────────────────────────────────────────────────────────────
185
- // Scenario 2 — Apple CONSUMPTION_REQUEST without provider configured
186
- // User has a consumable purchase. Apple sends CONSUMPTION_REQUEST.
187
- // Without an apple.consumptionInfoProvider hook, the webhook should:
188
- // - Not mutate the PurchaseStore (CONSUMPTION_REQUEST is a refund REVIEW,
189
- // not a confirmed refund — IAP row stays put)
190
- // - Not call the App Store Server API (no PUT)
191
- // - Still 200 to Apple
192
- // ─────────────────────────────────────────────────────────────────────────────
193
- describe('Scenario 2 — Apple CONSUMPTION_REQUEST without provider hook', () => {
194
- it('does not call Apple PUT, does not delete the consumable row, returns 200', async () => {
195
- const originalFetch = global.fetch;
196
- const outboundPuts = [];
197
- vi.spyOn(global, 'fetch').mockImplementation(async (url, init) => {
198
- if (isLocalhostUrl(url))
199
- return originalFetch(url, init);
200
- if (init?.method === 'PUT')
201
- outboundPuts.push(String(url));
202
- return { ok: true, status: 200, json: async () => ({}), text: async () => '' };
203
- });
204
- const config = {
205
- apple: { bundleId: 'com.example.app', skipJwsVerification: true }, // no API creds, no hook
206
- database: { url: '' },
207
- };
208
- const { purchaseStore, server } = buildServers(config);
209
- const txId = 'iap_consumable_under_review';
210
- await purchaseStore.savePurchase({
211
- userId: 'u_consume',
212
- productId: 'credits_100',
213
- platform: 'apple',
214
- type: 'consumable',
215
- transactionId: txId,
216
- purchasedAt: '2026-04-01T00:00:00.000Z',
217
- quantity: 1,
218
- });
219
- // CONSUMPTION_REQUEST is in APPLE_CANCELED_TYPES — for IAP it routes through
220
- // the deletePurchaseByTransactionId branch. Document this current behavior:
221
- // the row IS removed even on a refund REVIEW (not just confirmed REFUND).
222
- // If the host wants to defer removal until confirmation, they should set up
223
- // a consumptionInfoProvider that returns a custom decision.
224
- const resp = await server.webhook('/onesub/webhook/apple', applePayload('CONSUMPTION_REQUEST', {
225
- originalTransactionId: txId,
226
- transactionId: txId,
227
- type: 'Consumable',
228
- productId: 'credits_100',
229
- }));
230
- expect(resp.status).toBe(200);
231
- expect(outboundPuts).toHaveLength(0); // no Apple PUT (no provider configured)
232
- // Pinning current behavior: webhook removes the consumable on CONSUMPTION_REQUEST.
233
- // If we later want to keep the row until confirmed REFUND, this assertion flips.
234
- expect(await purchaseStore.getPurchaseByTransactionId(txId)).toBeNull();
235
- });
236
- it('with provider hook: provider invoked, PUT issued, row still removed', async () => {
237
- const originalFetch = global.fetch;
238
- const outboundPuts = [];
239
- vi.spyOn(global, 'fetch').mockImplementation(async (url, init) => {
240
- if (isLocalhostUrl(url))
241
- return originalFetch(url, init);
242
- if (init?.method === 'PUT')
243
- outboundPuts.push({ url: String(url), body: init.body });
244
- return { ok: true, status: 200, json: async () => ({}), text: async () => '' };
245
- });
246
- const provider = vi.fn(async (_ctx) => ({
247
- customerConsented: true,
248
- consumptionStatus: 3,
249
- deliveryStatus: 1,
250
- refundPreference: 2,
251
- }));
252
- const config = {
253
- apple: {
254
- bundleId: 'com.example.app',
255
- skipJwsVerification: true,
256
- keyId: 'KEY1',
257
- issuerId: 'iss-uuid',
258
- privateKey: testEcKey,
259
- consumptionInfoProvider: provider,
260
- },
261
- database: { url: '' },
262
- };
263
- const { purchaseStore, server } = buildServers(config);
264
- const txId = 'iap_with_provider';
265
- await purchaseStore.savePurchase({
266
- userId: 'u_provider',
267
- productId: 'credits_100',
268
- platform: 'apple',
269
- type: 'consumable',
270
- transactionId: txId,
271
- purchasedAt: '2026-04-01T00:00:00.000Z',
272
- quantity: 1,
273
- });
274
- await server.webhook('/onesub/webhook/apple', applePayload('CONSUMPTION_REQUEST', {
275
- originalTransactionId: txId,
276
- transactionId: txId,
277
- type: 'Consumable',
278
- productId: 'credits_100',
279
- }));
280
- await new Promise((r) => setTimeout(r, 50)); // hook is fire-and-forget
281
- expect(provider).toHaveBeenCalled();
282
- expect(outboundPuts).toHaveLength(1);
283
- expect(outboundPuts[0].url).toContain('/inApps/v1/transactions/consumption/');
284
- expect(JSON.parse(String(outboundPuts[0].body))).toMatchObject({
285
- customerConsented: true,
286
- refundPreference: 2,
287
- });
288
- });
289
- });
290
- // ─────────────────────────────────────────────────────────────────────────────
291
- // Scenario 3 — Google user-voluntary pause with auto-resume time
292
- // PURCHASED → PAUSED (with autoResumeTime) → RESTARTED
293
- // Status route should keep the autoResumeTime in the subscription payload while
294
- // paused, so the host can render "재개 예정" UX.
295
- // ─────────────────────────────────────────────────────────────────────────────
296
- describe('Scenario 3 — Google paused lifecycle with autoResumeTime', () => {
297
- it('PURCHASED → PAUSED (autoResumeTime surfaces) → RESTARTED', async () => {
298
- const config = {
299
- google: {
300
- packageName: 'com.example.app',
301
- serviceAccountKey: JSON.stringify({
302
- client_email: `sa-${Math.random()}@x.iam.gserviceaccount.com`,
303
- private_key: testRsaKey,
304
- token_uri: 'https://oauth2.googleapis.com/token',
305
- }),
306
- },
307
- database: { url: '' },
308
- };
309
- const tok = 'tok_google_pause';
310
- let v2Response = {
311
- startTime: '2026-01-01T00:00:00Z',
312
- subscriptionState: 'SUBSCRIPTION_STATE_ACTIVE',
313
- latestOrderId: 'GPA.active_1',
314
- lineItems: [{
315
- productId: 'pro_monthly',
316
- expiryTime: '2027-01-01T00:00:00Z',
317
- autoRenewingPlan: { autoRenewEnabled: true },
318
- }],
319
- };
320
- const originalFetch = global.fetch;
321
- vi.spyOn(global, 'fetch').mockImplementation(async (url, init) => {
322
- if (isLocalhostUrl(url))
323
- return originalFetch(url, init);
324
- const host = urlHost(url);
325
- if (host === 'oauth2.googleapis.com') {
326
- return { ok: true, json: async () => ({ access_token: 'tok', expires_in: 3600 }), text: async () => '' };
327
- }
328
- if (host === 'androidpublisher.googleapis.com') {
329
- return { ok: true, json: async () => v2Response, text: async () => '' };
330
- }
331
- throw new Error(`unexpected ${String(url)}`);
332
- });
333
- const { store, server } = buildServers(config);
334
- // Pre-seed an existing record (the unknown-tx fallback would otherwise
335
- // create one with a placeholder userId, which is fine but we want a real one).
336
- await store.save(sampleSub({
337
- platform: 'google',
338
- originalTransactionId: tok,
339
- userId: 'u_pause',
340
- }));
341
- // 1. PURCHASED — fresh re-fetch returns ACTIVE
342
- await server.webhook('/onesub/webhook/google', googlePush(4, tok));
343
- let saved = await store.getByTransactionId(tok);
344
- expect(saved?.status).toBe(SUBSCRIPTION_STATUS.ACTIVE);
345
- expect(saved?.autoResumeTime).toBeUndefined();
346
- expect((await server.status('u_pause')).active).toBe(true);
347
- // 2. PAUSED — v2 now returns PAUSED + autoResumeTime
348
- v2Response = {
349
- ...v2Response,
350
- subscriptionState: 'SUBSCRIPTION_STATE_PAUSED',
351
- pausedStateContext: { autoResumeTime: '2026-08-15T00:00:00Z' },
352
- };
353
- await server.webhook('/onesub/webhook/google', googlePush(10, tok));
354
- saved = await store.getByTransactionId(tok);
355
- expect(saved?.status).toBe(SUBSCRIPTION_STATUS.PAUSED);
356
- expect(saved?.autoResumeTime).toBe('2026-08-15T00:00:00Z');
357
- const pausedStatus = await server.status('u_pause');
358
- expect(pausedStatus.active).toBe(false); // entitlement revoked while paused
359
- expect(pausedStatus.subscription?.autoResumeTime).toBe('2026-08-15T00:00:00Z');
360
- // 3. RESTARTED — back to active, autoResumeTime cleared
361
- v2Response = {
362
- ...v2Response,
363
- subscriptionState: 'SUBSCRIPTION_STATE_ACTIVE',
364
- pausedStateContext: undefined,
365
- };
366
- await server.webhook('/onesub/webhook/google', googlePush(7, tok));
367
- saved = await store.getByTransactionId(tok);
368
- expect(saved?.status).toBe(SUBSCRIPTION_STATUS.ACTIVE);
369
- expect(saved?.autoResumeTime).toBeUndefined();
370
- expect((await server.status('u_pause')).active).toBe(true);
371
- });
372
- });
373
- // ─────────────────────────────────────────────────────────────────────────────
374
- // Scenario 4 — Google plan upgrade (linkedPurchaseToken continuity)
375
- // Monthly subscription (token=tok_M, user=u_link) → user upgrades to yearly →
376
- // new token (tok_Y) arrives via SUBSCRIPTION_PURCHASED with linkedPurchaseToken=tok_M.
377
- // The webhook's unknown-tx branch should look up tok_M, inherit u_link's userId
378
- // onto the new yearly record, and leave the monthly record intact (history).
379
- // ─────────────────────────────────────────────────────────────────────────────
380
- describe('Scenario 4 — Google plan upgrade userId continuity', () => {
381
- it('monthly → yearly: new record inherits userId, monthly history preserved', async () => {
382
- const config = {
383
- google: {
384
- packageName: 'com.example.app',
385
- serviceAccountKey: JSON.stringify({
386
- client_email: `sa-${Math.random()}@x.iam.gserviceaccount.com`,
387
- private_key: testRsaKey,
388
- token_uri: 'https://oauth2.googleapis.com/token',
389
- }),
390
- },
391
- database: { url: '' },
392
- };
393
- const tokM = 'tok_monthly';
394
- const tokY = 'tok_yearly';
395
- const v2Yearly = {
396
- startTime: '2026-04-01T00:00:00Z',
397
- subscriptionState: 'SUBSCRIPTION_STATE_ACTIVE',
398
- latestOrderId: 'GPA.yearly_first',
399
- linkedPurchaseToken: tokM,
400
- lineItems: [{
401
- productId: 'pro_yearly',
402
- expiryTime: '2027-04-01T00:00:00Z',
403
- autoRenewingPlan: { autoRenewEnabled: true },
404
- }],
405
- };
406
- const originalFetch = global.fetch;
407
- vi.spyOn(global, 'fetch').mockImplementation(async (url, init) => {
408
- if (isLocalhostUrl(url))
409
- return originalFetch(url, init);
410
- const host = urlHost(url);
411
- if (host === 'oauth2.googleapis.com') {
412
- return { ok: true, json: async () => ({ access_token: 'tok', expires_in: 3600 }), text: async () => '' };
413
- }
414
- return { ok: true, json: async () => v2Yearly, text: async () => '' };
415
- });
416
- const { store, server } = buildServers(config);
417
- // Pre-existing monthly subscription owned by u_link
418
- await store.save(sampleSub({
419
- platform: 'google',
420
- productId: 'pro_monthly',
421
- originalTransactionId: tokM,
422
- userId: 'u_link',
423
- }));
424
- // SUBSCRIPTION_PURCHASED for the new yearly token (unknown to store)
425
- await server.webhook('/onesub/webhook/google', googlePush(4, tokY, 'pro_yearly'));
426
- // New yearly record created under the v2-returned latestOrderId, userId inherited
427
- const newRec = await store.getByTransactionId('GPA.yearly_first');
428
- expect(newRec).not.toBeNull();
429
- expect(newRec?.userId).toBe('u_link'); // ← continuity
430
- expect(newRec?.productId).toBe('pro_yearly');
431
- expect(newRec?.linkedPurchaseToken).toBe(tokM);
432
- expect(newRec?.status).toBe(SUBSCRIPTION_STATUS.ACTIVE);
433
- // Old monthly record still findable (history preserved)
434
- const oldRec = await store.getByTransactionId(tokM);
435
- expect(oldRec).not.toBeNull();
436
- expect(oldRec?.productId).toBe('pro_monthly');
437
- });
438
- });
439
- // ─────────────────────────────────────────────────────────────────────────────
440
- // Scenario 5 — Apple subscription REFUND (default 'immediate' policy)
441
- // SUBSCRIBED → REFUND. status should flip to canceled right away, not on next
442
- // expiry. Status route reports active=false immediately. With refundPolicy
443
- // 'until_expiry', the same sequence keeps active=true until expiresAt — covered
444
- // in the second case for contrast.
445
- // ─────────────────────────────────────────────────────────────────────────────
446
- describe('Scenario 5 — Apple subscription REFUND (immediate vs until_expiry)', () => {
447
- it("default 'immediate': REFUND flips status=canceled, active=false now", async () => {
448
- const config = {
449
- apple: { bundleId: 'com.example.app', skipJwsVerification: true },
450
- database: { url: '' },
451
- };
452
- const { store, server } = buildServers(config);
453
- const orig = 'orig_refund_immediate';
454
- await store.save(sampleSub({ originalTransactionId: orig, userId: 'u_refund_imm' }));
455
- await server.webhook('/onesub/webhook/apple', applePayload('SUBSCRIBED', {
456
- originalTransactionId: orig,
457
- expiresDate: Date.now() + 30 * 86400000,
458
- }));
459
- expect((await server.status('u_refund_imm')).active).toBe(true);
460
- await server.webhook('/onesub/webhook/apple', applePayload('REFUND', {
461
- originalTransactionId: orig,
462
- expiresDate: Date.now() + 30 * 86400000,
463
- }));
464
- expect((await store.getByTransactionId(orig))?.status).toBe(SUBSCRIPTION_STATUS.CANCELED);
465
- expect((await server.status('u_refund_imm')).active).toBe(false);
466
- });
467
- it("'until_expiry': REFUND keeps status=active until expiresAt passes", async () => {
468
- const config = {
469
- apple: { bundleId: 'com.example.app', skipJwsVerification: true },
470
- database: { url: '' },
471
- refundPolicy: 'until_expiry',
472
- };
473
- const { store, server } = buildServers(config);
474
- const orig = 'orig_refund_keep';
475
- await store.save(sampleSub({
476
- originalTransactionId: orig,
477
- userId: 'u_refund_keep',
478
- expiresAt: futureExpiry,
479
- }));
480
- await server.webhook('/onesub/webhook/apple', applePayload('REFUND', {
481
- originalTransactionId: orig,
482
- expiresDate: Date.now() + 30 * 86400000,
483
- }));
484
- const after = await store.getByTransactionId(orig);
485
- expect(after?.status).toBe(SUBSCRIPTION_STATUS.ACTIVE); // status preserved
486
- expect(after?.willRenew).toBe(false); // willRenew flipped
487
- expect(after?.expiresAt).toBe(futureExpiry); // expiresAt preserved
488
- expect((await server.status('u_refund_keep')).active).toBe(true); // entitlement still valid
489
- });
490
- });
491
- // ─────────────────────────────────────────────────────────────────────────────
492
- // Scenario 6 — webhook for unknown originalTransactionId → Apple Status API fallback
493
- // The local store has no record (e.g. server downtime caused webhook miss). When
494
- // any notification arrives for that originalTransactionId, the webhook should:
495
- // - Detect the missing record
496
- // - Call fetchAppleSubscriptionStatus to get canonical state from Apple
497
- // - Save a record under originalTransactionId with placeholder userId
498
- // - Subsequent /onesub/validate from the host can claim ownership
499
- // ─────────────────────────────────────────────────────────────────────────────
500
- describe('Scenario 6 — webhook missed → Apple Status API fallback recovery', () => {
501
- it('unknown-tx notification triggers Status API fetch and saves a placeholder record', async () => {
502
- const orig = 'orig_recovered';
503
- const recoveredTx = makeJws({
504
- bundleId: 'com.example.app',
505
- productId: 'pro_monthly',
506
- transactionId: 'tx_recovered',
507
- originalTransactionId: orig,
508
- purchaseDate: Date.now() - 10 * 86400000,
509
- originalPurchaseDate: Date.now() - 10 * 86400000,
510
- expiresDate: Date.now() + 20 * 86400000,
511
- });
512
- const originalFetch = global.fetch;
513
- const apiCalls = [];
514
- vi.spyOn(global, 'fetch').mockImplementation(async (url, init) => {
515
- if (isLocalhostUrl(url))
516
- return originalFetch(url, init);
517
- const u = String(url);
518
- apiCalls.push(u);
519
- // Mock Apple Status API response
520
- return {
521
- ok: true,
522
- status: 200,
523
- json: async () => ({
524
- bundleId: 'com.example.app',
525
- environment: 'Production',
526
- data: [{
527
- lastTransactions: [{
528
- originalTransactionId: orig,
529
- status: 1, // Active
530
- signedTransactionInfo: recoveredTx,
531
- signedRenewalInfo: makeJws({ autoRenewStatus: 1 }),
532
- }],
533
- }],
534
- }),
535
- text: async () => '',
536
- };
537
- });
538
- const config = {
539
- apple: {
540
- bundleId: 'com.example.app',
541
- skipJwsVerification: true,
542
- keyId: 'K',
543
- issuerId: 'I',
544
- privateKey: testEcKey,
545
- },
546
- database: { url: '' },
547
- };
548
- const { store, server } = buildServers(config);
549
- // No pre-seed → store has no record for `orig`
550
- expect(await store.getByTransactionId(orig)).toBeNull();
551
- const resp = await server.webhook('/onesub/webhook/apple', applePayload('DID_RENEW', {
552
- originalTransactionId: orig,
553
- expiresDate: Date.now() + 20 * 86400000,
554
- }));
555
- expect(resp.status).toBe(200);
556
- // Status API was called as fallback
557
- expect(apiCalls.some((u) => u.includes('/inApps/v1/subscriptions/'))).toBe(true);
558
- // Record was created with placeholder userId = originalTransactionId
559
- const recovered = await store.getByTransactionId(orig);
560
- expect(recovered).not.toBeNull();
561
- expect(recovered?.status).toBe(SUBSCRIPTION_STATUS.ACTIVE);
562
- expect(recovered?.userId).toBe(orig); // placeholder until host /validate claims it
563
- });
564
- it('unknown-tx with no API credentials: logs and acks (no record created)', async () => {
565
- const config = {
566
- apple: { bundleId: 'com.example.app', skipJwsVerification: true }, // no API creds
567
- database: { url: '' },
568
- };
569
- const { store, server } = buildServers(config);
570
- const orig = 'orig_no_creds';
571
- const resp = await server.webhook('/onesub/webhook/apple', applePayload('DID_RENEW', {
572
- originalTransactionId: orig,
573
- expiresDate: Date.now() + 20 * 86400000,
574
- }));
575
- expect(resp.status).toBe(200); // ack so Apple doesn't retry forever
576
- expect(await store.getByTransactionId(orig)).toBeNull(); // can't recover without creds
577
- });
578
- });
579
- //# sourceMappingURL=lifecycle-scenarios.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"lifecycle-scenarios.test.js","sourceRoot":"","sources":["../../src/__tests__/lifecycle-scenarios.test.ts"],"names":[],"mappings":"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"}