@onesub/server 0.13.0 → 0.13.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.
- package/dist/__tests__/error-codes.test.js +8 -3
- package/dist/__tests__/error-codes.test.js.map +1 -1
- package/dist/__tests__/redis-store.test.js +58 -9
- package/dist/__tests__/redis-store.test.js.map +1 -1
- package/dist/__tests__/webhook-apple.test.js +247 -0
- package/dist/__tests__/webhook-apple.test.js.map +1 -0
- package/dist/__tests__/webhook-google.test.js +255 -0
- package/dist/__tests__/webhook-google.test.js.map +1 -0
- package/dist/cache.js +0 -4
- package/dist/cache.js.map +1 -1
- package/dist/index.cjs +10 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +10 -3
- package/dist/index.js.map +1 -1
- package/dist/providers/apple.js +121 -1
- package/dist/providers/apple.js.map +1 -1
- package/dist/providers/google.js +42 -0
- package/dist/providers/google.js.map +1 -1
- package/dist/routes/admin.js +40 -0
- package/dist/routes/admin.js.map +1 -1
- package/dist/routes/apple-offer.js +72 -0
- package/dist/routes/apple-offer.js.map +1 -0
- package/dist/routes/purchase.d.ts.map +1 -1
- package/dist/routes/purchase.js +21 -4
- package/dist/routes/purchase.js.map +1 -1
- package/dist/routes/webhook-apple.js +145 -0
- package/dist/routes/webhook-apple.js.map +1 -0
- package/dist/routes/webhook-google.js +204 -0
- package/dist/routes/webhook-google.js.map +1 -0
- package/dist/routes/webhook.js +9 -451
- package/dist/routes/webhook.js.map +1 -1
- package/dist/stores/redis.js +65 -23
- package/dist/stores/redis.js.map +1 -1
- package/dist/webhook-events.js +9 -8
- package/dist/webhook-events.js.map +1 -1
- package/package.json +3 -3
|
@@ -73,7 +73,7 @@ describe('server error codes', () => {
|
|
|
73
73
|
expect(res.status).toBe(400);
|
|
74
74
|
expect(res.body.errorCode).toBe(ONESUB_ERROR_CODE.INVALID_INPUT);
|
|
75
75
|
});
|
|
76
|
-
it('non-consumable already owned →
|
|
76
|
+
it('non-consumable already owned → 200 idempotent restore with recorded transactionId', async () => {
|
|
77
77
|
// Pre-seed the store with a purchase
|
|
78
78
|
const purchaseStore = new InMemoryPurchaseStore();
|
|
79
79
|
await purchaseStore.savePurchase({
|
|
@@ -99,8 +99,13 @@ describe('server error codes', () => {
|
|
|
99
99
|
productId: 'premium',
|
|
100
100
|
type: 'non_consumable',
|
|
101
101
|
});
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
// Owning a non-consumable IS success. The server returns the recorded
|
|
103
|
+
// purchase as a `restored` result — crucially WITH its transactionId — so
|
|
104
|
+
// downstream consumers can re-entitle instead of receiving a 409 + null.
|
|
105
|
+
expect(res.status).toBe(200);
|
|
106
|
+
expect(res.body.valid).toBe(true);
|
|
107
|
+
expect(res.body.action).toBe('restored');
|
|
108
|
+
expect(res.body.purchase.transactionId).toBe('tx_1');
|
|
104
109
|
});
|
|
105
110
|
});
|
|
106
111
|
// ── /onesub/webhook/apple ────────────────────────────────────
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-codes.test.js","sourceRoot":"","sources":["../../src/__tests__/error-codes.test.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"error-codes.test.js","sourceRoot":"","sources":["../../src/__tests__/error-codes.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { describe, expect, it, beforeEach } from 'vitest';
|
|
2
2
|
import IORedisMock from 'ioredis-mock';
|
|
3
|
-
import { RedisSubscriptionStore, RedisPurchaseStore, RedisCacheAdapter } from '../stores/redis.js';
|
|
3
|
+
import { RedisSubscriptionStore, RedisPurchaseStore, RedisCacheAdapter, RedisWebhookEventStore } from '../stores/redis.js';
|
|
4
4
|
import { SUBSCRIPTION_STATUS } from '@onesub/shared';
|
|
5
|
-
function makeRedis() {
|
|
5
|
+
async function makeRedis() {
|
|
6
6
|
// ioredis-mock's surface matches ioredis enough for our store's methods
|
|
7
7
|
// (set/get/zadd/zrevrange/sadd/smembers/multi). Cast to keep TS happy.
|
|
8
|
-
|
|
8
|
+
// The mock keeps a process-wide store across instances by default — flush
|
|
9
|
+
// so each test starts from a clean slate.
|
|
10
|
+
const r = new IORedisMock();
|
|
11
|
+
await r.flushall();
|
|
12
|
+
return r;
|
|
9
13
|
}
|
|
10
14
|
const baseSub = {
|
|
11
15
|
originalTransactionId: 'tx-1',
|
|
@@ -20,8 +24,8 @@ const baseSub = {
|
|
|
20
24
|
describe('RedisSubscriptionStore', () => {
|
|
21
25
|
let redis;
|
|
22
26
|
let store;
|
|
23
|
-
beforeEach(() => {
|
|
24
|
-
redis = makeRedis();
|
|
27
|
+
beforeEach(async () => {
|
|
28
|
+
redis = await makeRedis();
|
|
25
29
|
store = new RedisSubscriptionStore(redis);
|
|
26
30
|
});
|
|
27
31
|
it('save + getByTransactionId round-trip', async () => {
|
|
@@ -57,6 +61,29 @@ describe('RedisSubscriptionStore', () => {
|
|
|
57
61
|
expect(result.total).toBe(1);
|
|
58
62
|
expect(result.items[0].originalTransactionId).toBe('tx-a');
|
|
59
63
|
});
|
|
64
|
+
it('listFiltered pure pagination fast path returns correct total + page', async () => {
|
|
65
|
+
for (let i = 0; i < 5; i++) {
|
|
66
|
+
await store.save({ ...baseSub, originalTransactionId: `tx-p${i}`, userId: `user${i}` });
|
|
67
|
+
}
|
|
68
|
+
const page1 = await store.listFiltered({ limit: 2, offset: 0 });
|
|
69
|
+
expect(page1.total).toBe(5);
|
|
70
|
+
expect(page1.items).toHaveLength(2);
|
|
71
|
+
const page2 = await store.listFiltered({ limit: 2, offset: 2 });
|
|
72
|
+
expect(page2.total).toBe(5);
|
|
73
|
+
expect(page2.items).toHaveLength(2);
|
|
74
|
+
// pages should not overlap
|
|
75
|
+
const ids1 = page1.items.map((s) => s.originalTransactionId);
|
|
76
|
+
const ids2 = page2.items.map((s) => s.originalTransactionId);
|
|
77
|
+
expect(ids1.filter((id) => ids2.includes(id))).toHaveLength(0);
|
|
78
|
+
});
|
|
79
|
+
it('listAll returns items newest-first', async () => {
|
|
80
|
+
await store.save({ ...baseSub, originalTransactionId: 'tx-old' });
|
|
81
|
+
await new Promise((r) => setTimeout(r, 5));
|
|
82
|
+
await store.save({ ...baseSub, originalTransactionId: 'tx-new' });
|
|
83
|
+
const all = await store.listAll();
|
|
84
|
+
expect(all[0].originalTransactionId).toBe('tx-new');
|
|
85
|
+
expect(all[1].originalTransactionId).toBe('tx-old');
|
|
86
|
+
});
|
|
60
87
|
});
|
|
61
88
|
const basePurchase = {
|
|
62
89
|
transactionId: 'p-1',
|
|
@@ -70,8 +97,8 @@ const basePurchase = {
|
|
|
70
97
|
describe('RedisPurchaseStore', () => {
|
|
71
98
|
let redis;
|
|
72
99
|
let store;
|
|
73
|
-
beforeEach(() => {
|
|
74
|
-
redis = makeRedis();
|
|
100
|
+
beforeEach(async () => {
|
|
101
|
+
redis = await makeRedis();
|
|
75
102
|
store = new RedisPurchaseStore(redis);
|
|
76
103
|
});
|
|
77
104
|
it('savePurchase + getPurchaseByTransactionId round-trip', async () => {
|
|
@@ -105,13 +132,35 @@ describe('RedisPurchaseStore', () => {
|
|
|
105
132
|
});
|
|
106
133
|
describe('RedisCacheAdapter', () => {
|
|
107
134
|
it('round-trips with TTL', async () => {
|
|
108
|
-
const cache = new RedisCacheAdapter(makeRedis());
|
|
135
|
+
const cache = new RedisCacheAdapter(await makeRedis());
|
|
109
136
|
await cache.set('k', { token: 'abc' }, 60);
|
|
110
137
|
expect(await cache.get('k')).toEqual({ token: 'abc' });
|
|
111
138
|
});
|
|
112
139
|
it('returns null for missing keys', async () => {
|
|
113
|
-
const cache = new RedisCacheAdapter(makeRedis());
|
|
140
|
+
const cache = new RedisCacheAdapter(await makeRedis());
|
|
114
141
|
expect(await cache.get('absent')).toBeNull();
|
|
115
142
|
});
|
|
116
143
|
});
|
|
144
|
+
describe('RedisWebhookEventStore', () => {
|
|
145
|
+
it('returns true on first sighting', async () => {
|
|
146
|
+
const store = new RedisWebhookEventStore(await makeRedis());
|
|
147
|
+
expect(await store.markIfNew('apple', 'uuid-1')).toBe(true);
|
|
148
|
+
});
|
|
149
|
+
it('returns false on duplicate (atomic SET NX)', async () => {
|
|
150
|
+
const store = new RedisWebhookEventStore(await makeRedis());
|
|
151
|
+
expect(await store.markIfNew('apple', 'uuid-1')).toBe(true);
|
|
152
|
+
expect(await store.markIfNew('apple', 'uuid-1')).toBe(false);
|
|
153
|
+
});
|
|
154
|
+
it('namespaces apple vs google so the same id does not collide', async () => {
|
|
155
|
+
const store = new RedisWebhookEventStore(await makeRedis());
|
|
156
|
+
expect(await store.markIfNew('apple', 'shared-id')).toBe(true);
|
|
157
|
+
expect(await store.markIfNew('google', 'shared-id')).toBe(true);
|
|
158
|
+
});
|
|
159
|
+
it('different event ids are independent', async () => {
|
|
160
|
+
const store = new RedisWebhookEventStore(await makeRedis());
|
|
161
|
+
expect(await store.markIfNew('google', 'msg-1')).toBe(true);
|
|
162
|
+
expect(await store.markIfNew('google', 'msg-2')).toBe(true);
|
|
163
|
+
expect(await store.markIfNew('google', 'msg-1')).toBe(false);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
117
166
|
//# sourceMappingURL=redis-store.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"redis-store.test.js","sourceRoot":"","sources":["../../src/__tests__/redis-store.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC1D,OAAO,WAAW,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"redis-store.test.js","sourceRoot":"","sources":["../../src/__tests__/redis-store.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for webhook-apple.ts handler behaviors.
|
|
3
|
+
*
|
|
4
|
+
* Covers gaps not reached by lifecycle-scenarios or webhook-refund:
|
|
5
|
+
* - Input validation (missing / malformed signedPayload)
|
|
6
|
+
* - Webhook event deduplication via WebhookEventStore
|
|
7
|
+
* - DID_FAIL_TO_RENEW without GRACE_PERIOD subtype → on_hold
|
|
8
|
+
* - Notification type mappings: DID_RECOVER, OFFER_REDEEMED → active; EXPIRED → expired
|
|
9
|
+
* - Unknown notification type falls through to JWS transaction status
|
|
10
|
+
*/
|
|
11
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
12
|
+
import express from 'express';
|
|
13
|
+
import { SUBSCRIPTION_STATUS } from '@onesub/shared';
|
|
14
|
+
import { createWebhookRouter } from '../routes/webhook.js';
|
|
15
|
+
import { InMemorySubscriptionStore, InMemoryPurchaseStore } from '../store.js';
|
|
16
|
+
import { InMemoryWebhookEventStore } from '../webhook-events.js';
|
|
17
|
+
// ── helpers ──────────────────────────────────────────────────────────────────
|
|
18
|
+
function makeJws(payload) {
|
|
19
|
+
const header = Buffer.from(JSON.stringify({ alg: 'ES256' })).toString('base64url');
|
|
20
|
+
const body = Buffer.from(JSON.stringify(payload)).toString('base64url');
|
|
21
|
+
return `${header}.${body}.fakesig`;
|
|
22
|
+
}
|
|
23
|
+
function applePayload(opts) {
|
|
24
|
+
const signedTransactionInfo = makeJws({
|
|
25
|
+
bundleId: 'com.example.app',
|
|
26
|
+
type: opts.type ?? 'Auto-Renewable Subscription',
|
|
27
|
+
productId: 'pro_monthly',
|
|
28
|
+
transactionId: opts.transactionId ?? `tx_${Date.now()}`,
|
|
29
|
+
originalTransactionId: opts.originalTransactionId,
|
|
30
|
+
purchaseDate: Date.now() - 86400000,
|
|
31
|
+
expiresDate: opts.expiresDate ?? Date.now() + 30 * 86400000,
|
|
32
|
+
environment: 'Production',
|
|
33
|
+
});
|
|
34
|
+
const signedRenewalInfo = makeJws({ autoRenewStatus: opts.autoRenewStatus ?? 1 });
|
|
35
|
+
const inner = {
|
|
36
|
+
notificationType: opts.notificationType,
|
|
37
|
+
data: { signedTransactionInfo, signedRenewalInfo },
|
|
38
|
+
};
|
|
39
|
+
if (opts.subtype)
|
|
40
|
+
inner.subtype = opts.subtype;
|
|
41
|
+
if (opts.notificationUUID)
|
|
42
|
+
inner.notificationUUID = opts.notificationUUID;
|
|
43
|
+
return { signedPayload: makeJws(inner) };
|
|
44
|
+
}
|
|
45
|
+
const baseConfig = {
|
|
46
|
+
apple: { bundleId: 'com.example.app', skipJwsVerification: true },
|
|
47
|
+
database: { url: '' },
|
|
48
|
+
};
|
|
49
|
+
const sampleSub = (overrides) => ({
|
|
50
|
+
userId: 'user_a',
|
|
51
|
+
productId: 'pro_monthly',
|
|
52
|
+
platform: 'apple',
|
|
53
|
+
status: 'active',
|
|
54
|
+
expiresAt: '2099-01-01T00:00:00.000Z',
|
|
55
|
+
originalTransactionId: 'orig_a',
|
|
56
|
+
purchasedAt: '2026-01-01T00:00:00.000Z',
|
|
57
|
+
willRenew: true,
|
|
58
|
+
...overrides,
|
|
59
|
+
});
|
|
60
|
+
function buildServer(config, store, webhookEventStore) {
|
|
61
|
+
const app = express();
|
|
62
|
+
app.use(express.json());
|
|
63
|
+
app.use(createWebhookRouter(config, store, new InMemoryPurchaseStore(), webhookEventStore));
|
|
64
|
+
return {
|
|
65
|
+
async request(body) {
|
|
66
|
+
const srv = app.listen(0);
|
|
67
|
+
const port = srv.address().port;
|
|
68
|
+
try {
|
|
69
|
+
const resp = await fetch(`http://127.0.0.1:${port}/onesub/webhook/apple`, {
|
|
70
|
+
method: 'POST',
|
|
71
|
+
headers: { 'Content-Type': 'application/json' },
|
|
72
|
+
body: JSON.stringify(body),
|
|
73
|
+
});
|
|
74
|
+
const text = await resp.text();
|
|
75
|
+
let parsed = text;
|
|
76
|
+
try {
|
|
77
|
+
parsed = JSON.parse(text);
|
|
78
|
+
}
|
|
79
|
+
catch { /* keep as text */ }
|
|
80
|
+
return { status: resp.status, body: parsed };
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
await new Promise((r) => srv.close(() => r()));
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
// ── Input validation ─────────────────────────────────────────────────────────
|
|
89
|
+
describe('Apple webhook — input validation', () => {
|
|
90
|
+
it('returns 400 when signedPayload is missing', async () => {
|
|
91
|
+
const store = new InMemorySubscriptionStore();
|
|
92
|
+
const server = buildServer(baseConfig, store);
|
|
93
|
+
const resp = await server.request({});
|
|
94
|
+
expect(resp.status).toBe(400);
|
|
95
|
+
expect(resp.body.errorCode).toBe('MISSING_SIGNED_PAYLOAD');
|
|
96
|
+
});
|
|
97
|
+
it('returns 400 when signedPayload is not a valid JWS', async () => {
|
|
98
|
+
const store = new InMemorySubscriptionStore();
|
|
99
|
+
const server = buildServer(baseConfig, store);
|
|
100
|
+
// Not a 3-part dot-separated JWT — decodeJwt will throw
|
|
101
|
+
const resp = await server.request({ signedPayload: 'not-a-jws-string' });
|
|
102
|
+
expect(resp.status).toBe(400);
|
|
103
|
+
expect(resp.body.errorCode).toBe('INVALID_SIGNED_PAYLOAD');
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
// ── Deduplication ────────────────────────────────────────────────────────────
|
|
107
|
+
describe('Apple webhook — deduplication', () => {
|
|
108
|
+
let store;
|
|
109
|
+
let webhookEventStore;
|
|
110
|
+
let server;
|
|
111
|
+
beforeEach(() => {
|
|
112
|
+
store = new InMemorySubscriptionStore();
|
|
113
|
+
webhookEventStore = new InMemoryWebhookEventStore();
|
|
114
|
+
server = buildServer(baseConfig, store, webhookEventStore);
|
|
115
|
+
});
|
|
116
|
+
it('processes the first delivery and returns received=true', async () => {
|
|
117
|
+
await store.save(sampleSub({ originalTransactionId: 'orig_dedup' }));
|
|
118
|
+
const resp = await server.request(applePayload({
|
|
119
|
+
notificationType: 'DID_RENEW',
|
|
120
|
+
notificationUUID: 'uuid-apple-1',
|
|
121
|
+
originalTransactionId: 'orig_dedup',
|
|
122
|
+
}));
|
|
123
|
+
expect(resp.status).toBe(200);
|
|
124
|
+
expect(resp.body.received).toBe(true);
|
|
125
|
+
expect(resp.body.deduped).toBeUndefined();
|
|
126
|
+
});
|
|
127
|
+
it('returns deduped=true and skips store update on replay', async () => {
|
|
128
|
+
await store.save(sampleSub({ originalTransactionId: 'orig_dedup2', status: 'active' }));
|
|
129
|
+
const payload = applePayload({
|
|
130
|
+
notificationType: 'EXPIRED',
|
|
131
|
+
notificationUUID: 'uuid-apple-2',
|
|
132
|
+
originalTransactionId: 'orig_dedup2',
|
|
133
|
+
});
|
|
134
|
+
// First delivery — processed normally (EXPIRED → expired)
|
|
135
|
+
await server.request(payload);
|
|
136
|
+
expect((await store.getByTransactionId('orig_dedup2'))?.status).toBe(SUBSCRIPTION_STATUS.EXPIRED);
|
|
137
|
+
// Restore status to simulate what a store rollback would look like
|
|
138
|
+
await store.save(sampleSub({ originalTransactionId: 'orig_dedup2', status: 'active' }));
|
|
139
|
+
// Replayed delivery — must be skipped, store stays 'active'
|
|
140
|
+
const replay = await server.request(payload);
|
|
141
|
+
expect(replay.status).toBe(200);
|
|
142
|
+
expect(replay.body.deduped).toBe(true);
|
|
143
|
+
expect((await store.getByTransactionId('orig_dedup2'))?.status).toBe(SUBSCRIPTION_STATUS.ACTIVE);
|
|
144
|
+
});
|
|
145
|
+
it('does not deduplicate when no webhookEventStore is wired', async () => {
|
|
146
|
+
// Without webhookEventStore, every delivery is processed regardless of UUID
|
|
147
|
+
const serverNoDedup = buildServer(baseConfig, store);
|
|
148
|
+
await store.save(sampleSub({ originalTransactionId: 'orig_nodedup' }));
|
|
149
|
+
const payload = applePayload({
|
|
150
|
+
notificationType: 'EXPIRED',
|
|
151
|
+
notificationUUID: 'uuid-apple-3',
|
|
152
|
+
originalTransactionId: 'orig_nodedup',
|
|
153
|
+
});
|
|
154
|
+
await serverNoDedup.request(payload);
|
|
155
|
+
await store.save(sampleSub({ originalTransactionId: 'orig_nodedup', status: 'active' }));
|
|
156
|
+
const second = await serverNoDedup.request(payload);
|
|
157
|
+
expect(second.status).toBe(200);
|
|
158
|
+
expect(second.body.deduped).toBeUndefined();
|
|
159
|
+
// Second delivery processed → status changed
|
|
160
|
+
expect((await store.getByTransactionId('orig_nodedup'))?.status).toBe(SUBSCRIPTION_STATUS.EXPIRED);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
// ── Notification type → status mapping ──────────────────────────────────────
|
|
164
|
+
describe('Apple webhook — notification type mapping', () => {
|
|
165
|
+
let store;
|
|
166
|
+
let server;
|
|
167
|
+
beforeEach(() => {
|
|
168
|
+
store = new InMemorySubscriptionStore();
|
|
169
|
+
server = buildServer(baseConfig, store);
|
|
170
|
+
});
|
|
171
|
+
it('DID_FAIL_TO_RENEW without subtype → on_hold', async () => {
|
|
172
|
+
await store.save(sampleSub({ originalTransactionId: 'orig_fail' }));
|
|
173
|
+
await server.request(applePayload({
|
|
174
|
+
notificationType: 'DID_FAIL_TO_RENEW',
|
|
175
|
+
originalTransactionId: 'orig_fail',
|
|
176
|
+
}));
|
|
177
|
+
expect((await store.getByTransactionId('orig_fail'))?.status).toBe(SUBSCRIPTION_STATUS.ON_HOLD);
|
|
178
|
+
});
|
|
179
|
+
it('DID_FAIL_TO_RENEW + GRACE_PERIOD subtype → grace_period', async () => {
|
|
180
|
+
await store.save(sampleSub({ originalTransactionId: 'orig_grace' }));
|
|
181
|
+
await server.request(applePayload({
|
|
182
|
+
notificationType: 'DID_FAIL_TO_RENEW',
|
|
183
|
+
subtype: 'GRACE_PERIOD',
|
|
184
|
+
originalTransactionId: 'orig_grace',
|
|
185
|
+
}));
|
|
186
|
+
expect((await store.getByTransactionId('orig_grace'))?.status).toBe(SUBSCRIPTION_STATUS.GRACE_PERIOD);
|
|
187
|
+
});
|
|
188
|
+
it('DID_RECOVER → active', async () => {
|
|
189
|
+
await store.save(sampleSub({ originalTransactionId: 'orig_recover', status: 'on_hold' }));
|
|
190
|
+
await server.request(applePayload({
|
|
191
|
+
notificationType: 'DID_RECOVER',
|
|
192
|
+
originalTransactionId: 'orig_recover',
|
|
193
|
+
expiresDate: Date.now() + 30 * 86400000,
|
|
194
|
+
}));
|
|
195
|
+
expect((await store.getByTransactionId('orig_recover'))?.status).toBe(SUBSCRIPTION_STATUS.ACTIVE);
|
|
196
|
+
});
|
|
197
|
+
it('OFFER_REDEEMED → active', async () => {
|
|
198
|
+
await store.save(sampleSub({ originalTransactionId: 'orig_offer', status: 'expired' }));
|
|
199
|
+
await server.request(applePayload({
|
|
200
|
+
notificationType: 'OFFER_REDEEMED',
|
|
201
|
+
originalTransactionId: 'orig_offer',
|
|
202
|
+
expiresDate: Date.now() + 30 * 86400000,
|
|
203
|
+
}));
|
|
204
|
+
expect((await store.getByTransactionId('orig_offer'))?.status).toBe(SUBSCRIPTION_STATUS.ACTIVE);
|
|
205
|
+
});
|
|
206
|
+
it('EXPIRED → expired', async () => {
|
|
207
|
+
await store.save(sampleSub({ originalTransactionId: 'orig_exp' }));
|
|
208
|
+
await server.request(applePayload({
|
|
209
|
+
notificationType: 'EXPIRED',
|
|
210
|
+
originalTransactionId: 'orig_exp',
|
|
211
|
+
}));
|
|
212
|
+
expect((await store.getByTransactionId('orig_exp'))?.status).toBe(SUBSCRIPTION_STATUS.EXPIRED);
|
|
213
|
+
});
|
|
214
|
+
it('GRACE_PERIOD_EXPIRED → on_hold', async () => {
|
|
215
|
+
await store.save(sampleSub({ originalTransactionId: 'orig_gpe', status: 'grace_period' }));
|
|
216
|
+
await server.request(applePayload({
|
|
217
|
+
notificationType: 'GRACE_PERIOD_EXPIRED',
|
|
218
|
+
originalTransactionId: 'orig_gpe',
|
|
219
|
+
}));
|
|
220
|
+
expect((await store.getByTransactionId('orig_gpe'))?.status).toBe(SUBSCRIPTION_STATUS.ON_HOLD);
|
|
221
|
+
});
|
|
222
|
+
it('unknown notification type falls through to JWS transaction status', async () => {
|
|
223
|
+
// JWS has autoRenewStatus=1 and a future expiresDate → provider decodes as ACTIVE.
|
|
224
|
+
// The webhook maps unknown types to the decoded status.
|
|
225
|
+
await store.save(sampleSub({ originalTransactionId: 'orig_unk', status: 'expired' }));
|
|
226
|
+
await server.request(applePayload({
|
|
227
|
+
notificationType: 'PRICE_INCREASE_CONSENT', // not in any APPLE_*_TYPES set
|
|
228
|
+
originalTransactionId: 'orig_unk',
|
|
229
|
+
expiresDate: Date.now() + 30 * 86400000,
|
|
230
|
+
autoRenewStatus: 1,
|
|
231
|
+
}));
|
|
232
|
+
// Status comes from the decoded JWS renewal info (active/grace_period based on expiresDate)
|
|
233
|
+
// With a future expiresDate + autoRenewStatus=1, decodeAppleNotification returns active
|
|
234
|
+
expect((await store.getByTransactionId('orig_unk'))?.status).toBe(SUBSCRIPTION_STATUS.ACTIVE);
|
|
235
|
+
});
|
|
236
|
+
it('returns 200 even when originalTransactionId is unknown (no record in store)', async () => {
|
|
237
|
+
// Webhook should always ack — not found means we can't recover without API creds,
|
|
238
|
+
// but we still return 200 so Apple doesn't retry indefinitely.
|
|
239
|
+
const resp = await server.request(applePayload({
|
|
240
|
+
notificationType: 'DID_RENEW',
|
|
241
|
+
originalTransactionId: 'completely_unknown',
|
|
242
|
+
}));
|
|
243
|
+
expect(resp.status).toBe(200);
|
|
244
|
+
expect(resp.body.received).toBe(true);
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
//# sourceMappingURL=webhook-apple.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-apple.test.js","sourceRoot":"","sources":["../../src/__tests__/webhook-apple.test.ts"],"names":[],"mappings":"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"}
|