@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,112 +0,0 @@
1
- /**
2
- * GET /onesub/admin/subscriptions/:transactionId — single-record detail.
3
- *
4
- * Backs the dashboard's subscription detail page. Same auth contract as the
5
- * other /onesub/admin/* endpoints (X-Admin-Secret header).
6
- */
7
- import { describe, it, expect } from 'vitest';
8
- import express from 'express';
9
- import { createOneSubMiddleware, InMemorySubscriptionStore, InMemoryPurchaseStore } from '../index.js';
10
- function sub(overrides) {
11
- return {
12
- userId: 'u',
13
- productId: 'pro_monthly',
14
- platform: 'apple',
15
- status: 'active',
16
- expiresAt: '2099-01-01T00:00:00.000Z',
17
- purchasedAt: '2026-04-01T00:00:00.000Z',
18
- originalTransactionId: 'orig_default',
19
- willRenew: true,
20
- ...overrides,
21
- };
22
- }
23
- function spinUp(handler) {
24
- return {
25
- async get(path, headers) {
26
- const httpServer = handler.listen(0);
27
- const port = httpServer.address().port;
28
- try {
29
- const resp = await fetch(`http://127.0.0.1:${port}${path}`, { headers });
30
- const text = await resp.text();
31
- let parsed = text;
32
- try {
33
- parsed = JSON.parse(text);
34
- }
35
- catch { /* keep as text */ }
36
- return { status: resp.status, body: parsed };
37
- }
38
- finally {
39
- await new Promise((r) => httpServer.close(() => r()));
40
- }
41
- },
42
- };
43
- }
44
- function buildServer(opts) {
45
- const store = new InMemorySubscriptionStore();
46
- const purchaseStore = new InMemoryPurchaseStore();
47
- const config = {
48
- apple: { bundleId: 'com.example.app', skipJwsVerification: true },
49
- database: { url: '' },
50
- adminSecret: opts.adminSecret,
51
- };
52
- const app = express();
53
- app.use(createOneSubMiddleware({ ...config, store, purchaseStore }));
54
- return { store, server: spinUp(app) };
55
- }
56
- const SECRET = 's3cr3t';
57
- const AUTH = { 'x-admin-secret': SECRET };
58
- describe('GET /onesub/admin/subscriptions/:transactionId auth', () => {
59
- it('returns 404 when adminSecret is unset (router not mounted)', async () => {
60
- const { server } = buildServer({});
61
- const resp = await server.get('/onesub/admin/subscriptions/orig_xyz');
62
- expect(resp.status).toBe(404);
63
- });
64
- it('returns 401 INVALID_ADMIN_SECRET when header is missing or wrong', async () => {
65
- const { server } = buildServer({ adminSecret: SECRET });
66
- const noHeader = await server.get('/onesub/admin/subscriptions/orig_xyz');
67
- expect(noHeader.status).toBe(401);
68
- expect(noHeader.body.errorCode).toBe('INVALID_ADMIN_SECRET');
69
- const wrongHeader = await server.get('/onesub/admin/subscriptions/orig_xyz', { 'x-admin-secret': 'wrong' });
70
- expect(wrongHeader.status).toBe(401);
71
- });
72
- });
73
- describe('GET /onesub/admin/subscriptions/:transactionId basics', () => {
74
- it('returns the matching subscription', async () => {
75
- const { store, server } = buildServer({ adminSecret: SECRET });
76
- const target = sub({ userId: 'alice', originalTransactionId: 'orig_42' });
77
- await store.save(target);
78
- await store.save(sub({ userId: 'bob', originalTransactionId: 'orig_other' }));
79
- const resp = await server.get('/onesub/admin/subscriptions/orig_42', AUTH);
80
- expect(resp.status).toBe(200);
81
- expect(resp.body.originalTransactionId).toBe('orig_42');
82
- expect(resp.body.userId).toBe('alice');
83
- });
84
- it('returns 404 TRANSACTION_NOT_FOUND when the id is unknown', async () => {
85
- const { server } = buildServer({ adminSecret: SECRET });
86
- const resp = await server.get('/onesub/admin/subscriptions/orig_does_not_exist', AUTH);
87
- expect(resp.status).toBe(404);
88
- expect(resp.body.errorCode).toBe('TRANSACTION_NOT_FOUND');
89
- });
90
- it('does not collide with the list endpoint (no :transactionId)', async () => {
91
- const { store, server } = buildServer({ adminSecret: SECRET });
92
- await store.save(sub({ userId: 'a', originalTransactionId: 'orig_1' }));
93
- const list = await server.get('/onesub/admin/subscriptions', AUTH);
94
- expect(list.status).toBe(200);
95
- expect(list.body.items).toHaveLength(1);
96
- });
97
- it('preserves Google-only fields (linkedPurchaseToken, autoResumeTime)', async () => {
98
- const { store, server } = buildServer({ adminSecret: SECRET });
99
- await store.save(sub({
100
- platform: 'google',
101
- status: 'paused',
102
- originalTransactionId: 'orig_google',
103
- linkedPurchaseToken: 'prev_token',
104
- autoResumeTime: '2026-05-01T00:00:00.000Z',
105
- }));
106
- const resp = await server.get('/onesub/admin/subscriptions/orig_google', AUTH);
107
- expect(resp.status).toBe(200);
108
- expect(resp.body.linkedPurchaseToken).toBe('prev_token');
109
- expect(resp.body.autoResumeTime).toBe('2026-05-01T00:00:00.000Z');
110
- });
111
- });
112
- //# sourceMappingURL=admin-subscription-detail.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"admin-subscription-detail.test.js","sourceRoot":"","sources":["../../src/__tests__/admin-subscription-detail.test.ts"],"names":[],"mappings":"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"}
@@ -1,41 +0,0 @@
1
- import { X509Certificate } from 'node:crypto';
2
- import { describe, it, expect } from 'vitest';
3
- import { APPLE_ROOT_CA_G3_PEM, APPLE_ROOT_CA_PEMS, } from '../providers/apple-root-ca.js';
4
- /**
5
- * Protects against accidental deletion when Apple publishes Root CA G4 and
6
- * someone "replaces" G3 instead of appending. StoreKit 2 receipts signed
7
- * under the older root must keep validating after G4 ships.
8
- */
9
- describe('Apple Root CA bundle', () => {
10
- it('includes at least one root', () => {
11
- expect(APPLE_ROOT_CA_PEMS.length).toBeGreaterThan(0);
12
- });
13
- it('includes G3 verbatim (retained even after G4 is added)', () => {
14
- expect(APPLE_ROOT_CA_PEMS).toContain(APPLE_ROOT_CA_G3_PEM);
15
- });
16
- it('every bundled root is a parseable X.509 certificate', () => {
17
- for (const pem of APPLE_ROOT_CA_PEMS) {
18
- expect(() => new X509Certificate(pem)).not.toThrow();
19
- }
20
- });
21
- it('every bundled root is currently within its validity window', () => {
22
- const now = Date.now();
23
- for (const pem of APPLE_ROOT_CA_PEMS) {
24
- const cert = new X509Certificate(pem);
25
- const notBefore = Date.parse(cert.validFrom);
26
- const notAfter = Date.parse(cert.validTo);
27
- expect(notBefore).toBeLessThanOrEqual(now);
28
- expect(notAfter).toBeGreaterThan(now);
29
- }
30
- });
31
- it('G3 is self-signed by Apple (issuer matches subject)', () => {
32
- const cert = new X509Certificate(APPLE_ROOT_CA_G3_PEM);
33
- expect(cert.issuer).toBe(cert.subject);
34
- expect(cert.subject).toContain('Apple Root CA - G3');
35
- });
36
- it('no duplicate PEMs in the bundle', () => {
37
- const set = new Set(APPLE_ROOT_CA_PEMS);
38
- expect(set.size).toBe(APPLE_ROOT_CA_PEMS.length);
39
- });
40
- });
41
- //# sourceMappingURL=apple-root-ca.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"apple-root-ca.test.js","sourceRoot":"","sources":["../../src/__tests__/apple-root-ca.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AAEvC;;;;GAIG;AACH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,MAAM,CAAC,kBAAkB,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,KAAK,MAAM,GAAG,IAAI,kBAAkB,EAAE,CAAC;YACrC,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACvD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,GAAG,IAAI,kBAAkB,EAAE,CAAC;YACrC,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC;YACtC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC1C,MAAM,CAAC,SAAS,CAAC,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC;YAC3C,MAAM,CAAC,QAAQ,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QACxC,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,IAAI,GAAG,IAAI,eAAe,CAAC,oBAAoB,CAAC,CAAC;QACvD,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,kBAAkB,CAAC,CAAC;QACxC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1,345 +0,0 @@
1
- /**
2
- * Tests for fetchAppleSubscriptionStatus + the Apple webhook unknown-tx fallback.
3
- *
4
- * Covers:
5
- * - status code 1..5 → SubscriptionStatus mapping
6
- * - sandbox vs production host routing
7
- * - missing API credentials → returns null (no throw)
8
- * - HTTP error / empty data → returns null
9
- * - webhook receives notification for unknown originalTransactionId →
10
- * calls Status API + saves the returned record
11
- * - webhook unknown tx without API creds → no fetch, just logs
12
- */
13
- import { describe, it, expect, beforeAll, beforeEach, vi } from 'vitest';
14
- import express from 'express';
15
- import { generateKeyPairSync } from 'crypto';
16
- import { SUBSCRIPTION_STATUS } from '@onesub/shared';
17
- import { fetchAppleSubscriptionStatus } from '../providers/apple.js';
18
- import { createWebhookRouter } from '../routes/webhook.js';
19
- import { InMemorySubscriptionStore, InMemoryPurchaseStore } from '../store.js';
20
- import { isLocalhostUrl } from './test-utils.js';
21
- // ── helpers ─────────────────────────────────────────────────────────────────
22
- function makeJws(payload) {
23
- const header = Buffer.from(JSON.stringify({ alg: 'ES256' })).toString('base64url');
24
- const body = Buffer.from(JSON.stringify(payload)).toString('base64url');
25
- return `${header}.${body}.fakesig`;
26
- }
27
- let testEcKey;
28
- beforeAll(() => {
29
- const { privateKey } = generateKeyPairSync('ec', { namedCurve: 'P-256' });
30
- testEcKey = privateKey.export({ type: 'pkcs8', format: 'pem' });
31
- });
32
- beforeEach(() => {
33
- vi.restoreAllMocks();
34
- });
35
- function appleConfigWithApi(overrides) {
36
- return {
37
- bundleId: 'com.example.app',
38
- skipJwsVerification: true,
39
- keyId: 'TESTKEY1',
40
- issuerId: '12345678-1234-1234-1234-123456789012',
41
- privateKey: testEcKey,
42
- ...overrides,
43
- };
44
- }
45
- /**
46
- * Mock global fetch with localhost pass-through. Apple Status API requests
47
- * resolve to the provided body; localhost (our test http server) is forwarded
48
- * to the real fetch implementation.
49
- */
50
- function mockAppleStatusFetch(responseBody, opts) {
51
- const originalFetch = global.fetch;
52
- const calls = [];
53
- vi.spyOn(global, 'fetch').mockImplementation(async (url, init) => {
54
- if (isLocalhostUrl(url)) {
55
- return originalFetch(url, init);
56
- }
57
- const urlStr = String(url);
58
- calls.push({
59
- url: urlStr,
60
- method: init?.method,
61
- headers: init?.headers,
62
- });
63
- return {
64
- ok: (opts?.status ?? 200) < 400,
65
- status: opts?.status ?? 200,
66
- json: async () => responseBody,
67
- text: async () => JSON.stringify(responseBody),
68
- };
69
- });
70
- return calls;
71
- }
72
- function makeStatusResponse(opts) {
73
- const tx = makeJws({
74
- bundleId: 'com.example.app',
75
- type: 'Auto-Renewable Subscription',
76
- productId: opts.productId ?? 'pro_monthly',
77
- transactionId: 'tx_inner',
78
- originalTransactionId: opts.originalTransactionId,
79
- purchaseDate: Date.now() - 30 * 86400000,
80
- originalPurchaseDate: Date.now() - 30 * 86400000,
81
- expiresDate: opts.expiresDate ?? Date.now() + 86400000,
82
- });
83
- const renewal = makeJws({ autoRenewStatus: opts.autoRenewStatus ?? 1 });
84
- return {
85
- bundleId: 'com.example.app',
86
- environment: 'Production',
87
- data: [{
88
- subscriptionGroupIdentifier: 'group_a',
89
- lastTransactions: [{
90
- originalTransactionId: opts.originalTransactionId,
91
- status: opts.status,
92
- signedTransactionInfo: tx,
93
- signedRenewalInfo: renewal,
94
- }],
95
- }],
96
- };
97
- }
98
- // ── fetchAppleSubscriptionStatus unit tests ─────────────────────────────────
99
- describe('fetchAppleSubscriptionStatus', () => {
100
- it('returns null when API credentials are missing', async () => {
101
- const fetchSpy = vi.spyOn(global, 'fetch');
102
- const result = await fetchAppleSubscriptionStatus('orig_xyz', {
103
- bundleId: 'com.example.app',
104
- skipJwsVerification: true,
105
- });
106
- expect(result).toBeNull();
107
- expect(fetchSpy).not.toHaveBeenCalled();
108
- });
109
- it('returns null when mockMode is enabled', async () => {
110
- const fetchSpy = vi.spyOn(global, 'fetch');
111
- const result = await fetchAppleSubscriptionStatus('orig_xyz', appleConfigWithApi({ mockMode: true }));
112
- expect(result).toBeNull();
113
- expect(fetchSpy).not.toHaveBeenCalled();
114
- });
115
- it('GET .../inApps/v1/subscriptions/<id> with Bearer JWT', async () => {
116
- const calls = mockAppleStatusFetch(makeStatusResponse({
117
- originalTransactionId: 'orig_active',
118
- status: 1,
119
- }));
120
- await fetchAppleSubscriptionStatus('orig_active', appleConfigWithApi());
121
- expect(calls).toHaveLength(1);
122
- expect(calls[0].url).toContain('api.storekit.itunes.apple.com');
123
- expect(calls[0].url).toContain('/inApps/v1/subscriptions/orig_active');
124
- expect(calls[0].headers?.Authorization).toMatch(/^Bearer /);
125
- });
126
- it('routes to sandbox host when options.sandbox is true', async () => {
127
- const calls = mockAppleStatusFetch(makeStatusResponse({
128
- originalTransactionId: 'orig_sb',
129
- status: 1,
130
- }));
131
- await fetchAppleSubscriptionStatus('orig_sb', appleConfigWithApi(), { sandbox: true });
132
- expect(calls[0].url).toContain('api.storekit-sandbox.itunes.apple.com');
133
- });
134
- it('maps status code 1 → active', async () => {
135
- mockAppleStatusFetch(makeStatusResponse({ originalTransactionId: 'o1', status: 1 }));
136
- const result = await fetchAppleSubscriptionStatus('o1', appleConfigWithApi());
137
- expect(result?.status).toBe(SUBSCRIPTION_STATUS.ACTIVE);
138
- });
139
- it('maps status code 2 → expired', async () => {
140
- mockAppleStatusFetch(makeStatusResponse({ originalTransactionId: 'o2', status: 2 }));
141
- const result = await fetchAppleSubscriptionStatus('o2', appleConfigWithApi());
142
- expect(result?.status).toBe(SUBSCRIPTION_STATUS.EXPIRED);
143
- });
144
- it('maps status code 3 → on_hold (billing retry)', async () => {
145
- mockAppleStatusFetch(makeStatusResponse({ originalTransactionId: 'o3', status: 3 }));
146
- const result = await fetchAppleSubscriptionStatus('o3', appleConfigWithApi());
147
- expect(result?.status).toBe(SUBSCRIPTION_STATUS.ON_HOLD);
148
- });
149
- it('maps status code 4 → grace_period', async () => {
150
- mockAppleStatusFetch(makeStatusResponse({ originalTransactionId: 'o4', status: 4 }));
151
- const result = await fetchAppleSubscriptionStatus('o4', appleConfigWithApi());
152
- expect(result?.status).toBe(SUBSCRIPTION_STATUS.GRACE_PERIOD);
153
- });
154
- it('maps status code 5 → canceled (revoked)', async () => {
155
- mockAppleStatusFetch(makeStatusResponse({ originalTransactionId: 'o5', status: 5 }));
156
- const result = await fetchAppleSubscriptionStatus('o5', appleConfigWithApi());
157
- expect(result?.status).toBe(SUBSCRIPTION_STATUS.CANCELED);
158
- });
159
- it('reads autoRenewStatus from signedRenewalInfo for willRenew', async () => {
160
- mockAppleStatusFetch(makeStatusResponse({
161
- originalTransactionId: 'o_renew',
162
- status: 1,
163
- autoRenewStatus: 0,
164
- }));
165
- const result = await fetchAppleSubscriptionStatus('o_renew', appleConfigWithApi());
166
- expect(result?.willRenew).toBe(false);
167
- });
168
- it('returns null on HTTP 404', async () => {
169
- mockAppleStatusFetch({ errorCode: 4040010 }, { status: 404 });
170
- const result = await fetchAppleSubscriptionStatus('not_found', appleConfigWithApi());
171
- expect(result).toBeNull();
172
- });
173
- it('returns null when data array is empty', async () => {
174
- mockAppleStatusFetch({ bundleId: 'com.example.app', environment: 'Production', data: [] });
175
- const result = await fetchAppleSubscriptionStatus('orig_empty', appleConfigWithApi());
176
- expect(result).toBeNull();
177
- });
178
- it('returns null when matching originalTransactionId not in lastTransactions', async () => {
179
- mockAppleStatusFetch({
180
- bundleId: 'com.example.app',
181
- environment: 'Production',
182
- data: [{
183
- subscriptionGroupIdentifier: 'g',
184
- lastTransactions: [{
185
- originalTransactionId: 'different_id',
186
- status: 1,
187
- signedTransactionInfo: makeJws({ productId: 'p', expiresDate: Date.now() }),
188
- }],
189
- }],
190
- });
191
- const result = await fetchAppleSubscriptionStatus('expected_id', appleConfigWithApi());
192
- expect(result).toBeNull();
193
- });
194
- it('preserves originalTransactionId from caller (not from inner JWS)', async () => {
195
- mockAppleStatusFetch(makeStatusResponse({
196
- originalTransactionId: 'orig_caller',
197
- status: 1,
198
- }));
199
- const result = await fetchAppleSubscriptionStatus('orig_caller', appleConfigWithApi());
200
- expect(result?.originalTransactionId).toBe('orig_caller');
201
- });
202
- });
203
- function buildAppleWebhookServer(config) {
204
- const store = new InMemorySubscriptionStore();
205
- const purchaseStore = new InMemoryPurchaseStore();
206
- const app = express();
207
- app.use(express.json());
208
- app.use(createWebhookRouter(config, store, purchaseStore));
209
- return {
210
- store,
211
- server: {
212
- async request(path, body) {
213
- const httpServer = app.listen(0);
214
- const address = httpServer.address();
215
- const port = typeof address === 'object' && address ? address.port : 0;
216
- try {
217
- const resp = await fetch(`http://127.0.0.1:${port}${path}`, {
218
- method: 'POST',
219
- headers: { 'Content-Type': 'application/json' },
220
- body: JSON.stringify(body),
221
- });
222
- const text = await resp.text();
223
- let parsed = text;
224
- try {
225
- parsed = JSON.parse(text);
226
- }
227
- catch { /* keep as text */ }
228
- return { status: resp.status, body: parsed };
229
- }
230
- finally {
231
- await new Promise((resolve) => httpServer.close(() => resolve()));
232
- }
233
- },
234
- },
235
- };
236
- }
237
- function buildUnknownTxNotification(originalTransactionId, opts) {
238
- const signedTransactionInfo = makeJws({
239
- bundleId: 'com.example.app',
240
- type: 'Auto-Renewable Subscription',
241
- productId: 'pro_monthly',
242
- transactionId: 'tx_notify',
243
- originalTransactionId,
244
- purchaseDate: Date.now(),
245
- expiresDate: Date.now() + 86400000,
246
- environment: opts?.sandbox ? 'Sandbox' : 'Production',
247
- });
248
- return {
249
- signedPayload: makeJws({
250
- notificationType: 'DID_RENEW',
251
- data: {
252
- signedTransactionInfo,
253
- signedRenewalInfo: makeJws({ autoRenewStatus: 1 }),
254
- },
255
- }),
256
- };
257
- }
258
- describe('Apple webhook — unknown originalTransactionId fallback', () => {
259
- it('fetches from Status API and saves a placeholder record when API creds present', async () => {
260
- mockAppleStatusFetch(makeStatusResponse({
261
- originalTransactionId: 'orig_unknown',
262
- status: 1,
263
- }));
264
- const config = {
265
- apple: appleConfigWithApi(),
266
- database: { url: '' },
267
- };
268
- const { store, server } = buildAppleWebhookServer(config);
269
- const resp = await server.request('/onesub/webhook/apple', buildUnknownTxNotification('orig_unknown'));
270
- expect(resp.status).toBe(200);
271
- const saved = await store.getByTransactionId('orig_unknown');
272
- expect(saved).not.toBeNull();
273
- expect(saved?.status).toBe(SUBSCRIPTION_STATUS.ACTIVE);
274
- // userId is unknown at webhook time — placeholder is the originalTransactionId
275
- expect(saved?.userId).toBe('orig_unknown');
276
- });
277
- it('routes to sandbox host when notification environment is Sandbox', async () => {
278
- const calls = mockAppleStatusFetch(makeStatusResponse({
279
- originalTransactionId: 'orig_sb_unknown',
280
- status: 1,
281
- }));
282
- const config = {
283
- apple: appleConfigWithApi(),
284
- database: { url: '' },
285
- };
286
- const { server } = buildAppleWebhookServer(config);
287
- await server.request('/onesub/webhook/apple', buildUnknownTxNotification('orig_sb_unknown', { sandbox: true }));
288
- const apiCall = calls.find((c) => c.url.includes('/inApps/v1/subscriptions/'));
289
- expect(apiCall?.url).toContain('api.storekit-sandbox.itunes.apple.com');
290
- });
291
- it('does not call Status API when issuerId/keyId/privateKey are missing', async () => {
292
- const originalFetch = global.fetch;
293
- const outboundCalls = [];
294
- vi.spyOn(global, 'fetch').mockImplementation(async (url, init) => {
295
- if (isLocalhostUrl(url)) {
296
- return originalFetch(url, init);
297
- }
298
- outboundCalls.push({ url: String(url) });
299
- return { ok: true, status: 200, json: async () => ({}), text: async () => '' };
300
- });
301
- const config = {
302
- apple: { bundleId: 'com.example.app', skipJwsVerification: true }, // no API creds
303
- database: { url: '' },
304
- };
305
- const { store, server } = buildAppleWebhookServer(config);
306
- const resp = await server.request('/onesub/webhook/apple', buildUnknownTxNotification('orig_no_creds'));
307
- expect(resp.status).toBe(200);
308
- expect(await store.getByTransactionId('orig_no_creds')).toBeNull();
309
- expect(outboundCalls).toHaveLength(0);
310
- });
311
- it('does not overwrite an existing record (still the normal update path)', async () => {
312
- const originalFetch = global.fetch;
313
- const outboundCalls = [];
314
- vi.spyOn(global, 'fetch').mockImplementation(async (url, init) => {
315
- if (isLocalhostUrl(url)) {
316
- return originalFetch(url, init);
317
- }
318
- outboundCalls.push({ url: String(url) });
319
- return { ok: true, status: 200, json: async () => ({}), text: async () => '' };
320
- });
321
- const config = {
322
- apple: appleConfigWithApi(),
323
- database: { url: '' },
324
- };
325
- const { store, server } = buildAppleWebhookServer(config);
326
- const existing = {
327
- userId: 'real_user',
328
- productId: 'pro_monthly',
329
- platform: 'apple',
330
- status: SUBSCRIPTION_STATUS.ACTIVE,
331
- expiresAt: '2027-01-01T00:00:00.000Z',
332
- originalTransactionId: 'orig_known',
333
- purchasedAt: '2026-01-01T00:00:00.000Z',
334
- willRenew: true,
335
- };
336
- await store.save(existing);
337
- const resp = await server.request('/onesub/webhook/apple', buildUnknownTxNotification('orig_known'));
338
- expect(resp.status).toBe(200);
339
- // Existing record's userId preserved (not replaced with placeholder)
340
- expect((await store.getByTransactionId('orig_known'))?.userId).toBe('real_user');
341
- // No outbound Status API call since we already had the record
342
- expect(outboundCalls.find((c) => c.url.includes('/inApps/v1/subscriptions/'))).toBeUndefined();
343
- });
344
- });
345
- //# sourceMappingURL=apple-status-api.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"apple-status-api.test.js","sourceRoot":"","sources":["../../src/__tests__/apple-status-api.test.ts"],"names":[],"mappings":"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"}
@@ -1,34 +0,0 @@
1
- import { describe, expect, it } from 'vitest';
2
- import { InMemoryCacheAdapter } from '../cache.js';
3
- describe('InMemoryCacheAdapter', () => {
4
- it('returns null for missing keys', async () => {
5
- const cache = new InMemoryCacheAdapter();
6
- expect(await cache.get('absent')).toBeNull();
7
- });
8
- it('round-trips a value', async () => {
9
- const cache = new InMemoryCacheAdapter();
10
- await cache.set('k', { token: 'abc', n: 1 });
11
- expect(await cache.get('k')).toEqual({ token: 'abc', n: 1 });
12
- });
13
- it('expires entries after the TTL elapses', async () => {
14
- const cache = new InMemoryCacheAdapter();
15
- await cache.set('k', 'v', 1);
16
- expect(await cache.get('k')).toBe('v');
17
- // Force expiry by moving the clock forward via a sleep substitute.
18
- await new Promise((resolve) => setTimeout(resolve, 1100));
19
- expect(await cache.get('k')).toBeNull();
20
- });
21
- it('treats ttl=0 / undefined as no-expiry', async () => {
22
- const cache = new InMemoryCacheAdapter();
23
- await cache.set('forever', 'v');
24
- await new Promise((resolve) => setTimeout(resolve, 50));
25
- expect(await cache.get('forever')).toBe('v');
26
- });
27
- it('del removes a key', async () => {
28
- const cache = new InMemoryCacheAdapter();
29
- await cache.set('k', 'v');
30
- await cache.del('k');
31
- expect(await cache.get('k')).toBeNull();
32
- });
33
- });
34
- //# sourceMappingURL=cache.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cache.test.js","sourceRoot":"","sources":["../../src/__tests__/cache.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAEnD,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,KAAK,GAAG,IAAI,oBAAoB,EAAE,CAAC;QACzC,MAAM,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qBAAqB,EAAE,KAAK,IAAI,EAAE;QACnC,MAAM,KAAK,GAAG,IAAI,oBAAoB,EAAE,CAAC;QACzC,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,KAAK,GAAG,IAAI,oBAAoB,EAAE,CAAC;QACzC,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACvC,mEAAmE;QACnE,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;QAC1D,MAAM,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,KAAK,GAAG,IAAI,oBAAoB,EAAE,CAAC;QACzC,MAAM,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAChC,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;QACxD,MAAM,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;QACjC,MAAM,KAAK,GAAG,IAAI,oBAAoB,EAAE,CAAC;QACzC,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC1B,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACrB,MAAM,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC1C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}