@onesub/server 0.13.1 → 0.15.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 (141) hide show
  1. package/dist/__tests__/google-subscriptions-v2.test.d.ts +1 -1
  2. package/dist/__tests__/tracing.test.d.ts +2 -0
  3. package/dist/__tests__/tracing.test.d.ts.map +1 -0
  4. package/dist/cache.d.ts +5 -0
  5. package/dist/cache.d.ts.map +1 -1
  6. package/dist/index.cjs +197 -52
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.js +197 -52
  9. package/dist/index.js.map +1 -1
  10. package/dist/providers/apple.d.ts +8 -0
  11. package/dist/providers/apple.d.ts.map +1 -1
  12. package/dist/providers/google.d.ts +8 -0
  13. package/dist/providers/google.d.ts.map +1 -1
  14. package/dist/providers/mock.d.ts +2 -0
  15. package/dist/providers/mock.d.ts.map +1 -1
  16. package/dist/routes/admin.d.ts.map +1 -1
  17. package/dist/routes/purchase.d.ts.map +1 -1
  18. package/dist/routes/validate.d.ts.map +1 -1
  19. package/dist/routes/webhook-apple.d.ts.map +1 -1
  20. package/dist/routes/webhook-google.d.ts +1 -1
  21. package/dist/routes/webhook-google.d.ts.map +1 -1
  22. package/dist/store.d.ts.map +1 -1
  23. package/dist/stores/postgres.d.ts.map +1 -1
  24. package/dist/stores/redis.d.ts +1 -0
  25. package/dist/stores/redis.d.ts.map +1 -1
  26. package/dist/tracing.d.ts.map +1 -1
  27. package/dist/webhook-events.d.ts +10 -0
  28. package/dist/webhook-events.d.ts.map +1 -1
  29. package/package.json +2 -2
  30. package/dist/__tests__/admin-customer-detail.test.js +0 -146
  31. package/dist/__tests__/admin-customer-detail.test.js.map +0 -1
  32. package/dist/__tests__/admin-list-subscriptions.test.js +0 -192
  33. package/dist/__tests__/admin-list-subscriptions.test.js.map +0 -1
  34. package/dist/__tests__/admin-subscription-detail.test.js +0 -112
  35. package/dist/__tests__/admin-subscription-detail.test.js.map +0 -1
  36. package/dist/__tests__/apple-root-ca.test.js +0 -41
  37. package/dist/__tests__/apple-root-ca.test.js.map +0 -1
  38. package/dist/__tests__/apple-status-api.test.js +0 -345
  39. package/dist/__tests__/apple-status-api.test.js.map +0 -1
  40. package/dist/__tests__/cache.test.js +0 -34
  41. package/dist/__tests__/cache.test.js.map +0 -1
  42. package/dist/__tests__/entitlements.test.js +0 -268
  43. package/dist/__tests__/entitlements.test.js.map +0 -1
  44. package/dist/__tests__/error-codes.test.js +0 -173
  45. package/dist/__tests__/error-codes.test.js.map +0 -1
  46. package/dist/__tests__/fetch-hardening.test.js +0 -192
  47. package/dist/__tests__/fetch-hardening.test.js.map +0 -1
  48. package/dist/__tests__/google-paused.test.js +0 -126
  49. package/dist/__tests__/google-paused.test.js.map +0 -1
  50. package/dist/__tests__/google-price-change.test.js +0 -186
  51. package/dist/__tests__/google-price-change.test.js.map +0 -1
  52. package/dist/__tests__/google-subscriptions-v2.test.js +0 -206
  53. package/dist/__tests__/google-subscriptions-v2.test.js.map +0 -1
  54. package/dist/__tests__/lifecycle-scenarios.test.js +0 -579
  55. package/dist/__tests__/lifecycle-scenarios.test.js.map +0 -1
  56. package/dist/__tests__/lifecycle-states.test.js +0 -423
  57. package/dist/__tests__/lifecycle-states.test.js.map +0 -1
  58. package/dist/__tests__/linked-purchase-token.test.js +0 -227
  59. package/dist/__tests__/linked-purchase-token.test.js.map +0 -1
  60. package/dist/__tests__/metrics.test.js +0 -340
  61. package/dist/__tests__/metrics.test.js.map +0 -1
  62. package/dist/__tests__/mock-provider.test.js +0 -188
  63. package/dist/__tests__/mock-provider.test.js.map +0 -1
  64. package/dist/__tests__/openapi.test.js +0 -32
  65. package/dist/__tests__/openapi.test.js.map +0 -1
  66. package/dist/__tests__/paused-auto-resume.test.js +0 -162
  67. package/dist/__tests__/paused-auto-resume.test.js.map +0 -1
  68. package/dist/__tests__/providers.test.js +0 -321
  69. package/dist/__tests__/providers.test.js.map +0 -1
  70. package/dist/__tests__/redis-store.test.js +0 -166
  71. package/dist/__tests__/redis-store.test.js.map +0 -1
  72. package/dist/__tests__/refund-policy.test.js +0 -317
  73. package/dist/__tests__/refund-policy.test.js.map +0 -1
  74. package/dist/__tests__/schema.test.js +0 -46
  75. package/dist/__tests__/schema.test.js.map +0 -1
  76. package/dist/__tests__/store.test.js +0 -172
  77. package/dist/__tests__/store.test.js.map +0 -1
  78. package/dist/__tests__/test-utils.js +0 -30
  79. package/dist/__tests__/test-utils.js.map +0 -1
  80. package/dist/__tests__/webhook-apple.test.js +0 -247
  81. package/dist/__tests__/webhook-apple.test.js.map +0 -1
  82. package/dist/__tests__/webhook-events.test.js +0 -36
  83. package/dist/__tests__/webhook-events.test.js.map +0 -1
  84. package/dist/__tests__/webhook-google.test.js +0 -255
  85. package/dist/__tests__/webhook-google.test.js.map +0 -1
  86. package/dist/__tests__/webhook-queue.test.js +0 -26
  87. package/dist/__tests__/webhook-queue.test.js.map +0 -1
  88. package/dist/__tests__/webhook-refund.test.js +0 -313
  89. package/dist/__tests__/webhook-refund.test.js.map +0 -1
  90. package/dist/cache.js +0 -39
  91. package/dist/cache.js.map +0 -1
  92. package/dist/errors.js +0 -19
  93. package/dist/errors.js.map +0 -1
  94. package/dist/http.js +0 -36
  95. package/dist/http.js.map +0 -1
  96. package/dist/logger.js +0 -20
  97. package/dist/logger.js.map +0 -1
  98. package/dist/openapi.js +0 -196
  99. package/dist/openapi.js.map +0 -1
  100. package/dist/providers/apple-root-ca.js +0 -38
  101. package/dist/providers/apple-root-ca.js.map +0 -1
  102. package/dist/providers/apple.js +0 -630
  103. package/dist/providers/apple.js.map +0 -1
  104. package/dist/providers/google.js +0 -564
  105. package/dist/providers/google.js.map +0 -1
  106. package/dist/providers/mock.js +0 -93
  107. package/dist/providers/mock.js.map +0 -1
  108. package/dist/routes/admin.js +0 -327
  109. package/dist/routes/admin.js.map +0 -1
  110. package/dist/routes/apple-offer.js +0 -72
  111. package/dist/routes/apple-offer.js.map +0 -1
  112. package/dist/routes/entitlements.js +0 -130
  113. package/dist/routes/entitlements.js.map +0 -1
  114. package/dist/routes/metrics.js +0 -281
  115. package/dist/routes/metrics.js.map +0 -1
  116. package/dist/routes/purchase.js +0 -204
  117. package/dist/routes/purchase.js.map +0 -1
  118. package/dist/routes/status.js +0 -55
  119. package/dist/routes/status.js.map +0 -1
  120. package/dist/routes/validate.js +0 -70
  121. package/dist/routes/validate.js.map +0 -1
  122. package/dist/routes/webhook-apple.js +0 -145
  123. package/dist/routes/webhook-apple.js.map +0 -1
  124. package/dist/routes/webhook-google.js +0 -204
  125. package/dist/routes/webhook-google.js.map +0 -1
  126. package/dist/routes/webhook.js +0 -19
  127. package/dist/routes/webhook.js.map +0 -1
  128. package/dist/store.js +0 -145
  129. package/dist/store.js.map +0 -1
  130. package/dist/stores/postgres.js +0 -329
  131. package/dist/stores/postgres.js.map +0 -1
  132. package/dist/stores/redis.js +0 -297
  133. package/dist/stores/redis.js.map +0 -1
  134. package/dist/stores/schema.js +0 -67
  135. package/dist/stores/schema.js.map +0 -1
  136. package/dist/tracing.js +0 -74
  137. package/dist/tracing.js.map +0 -1
  138. package/dist/webhook-events.js +0 -58
  139. package/dist/webhook-events.js.map +0 -1
  140. package/dist/webhook-queue.js +0 -108
  141. package/dist/webhook-queue.js.map +0 -1
@@ -1,70 +0,0 @@
1
- import { Router } from 'express';
2
- import { z } from 'zod';
3
- import { ROUTES, ONESUB_ERROR_CODE } from '@onesub/shared';
4
- import { validateAppleReceipt } from '../providers/apple.js';
5
- import { validateGoogleReceipt, acknowledgeGoogleSubscription } from '../providers/google.js';
6
- import { log } from '../logger.js';
7
- import { sendError, sendZodError } from '../errors.js';
8
- const NO_SUB = { valid: false, subscription: null };
9
- const validateSchema = z.object({
10
- platform: z.enum(['apple', 'google']),
11
- receipt: z.string().min(1).max(10000),
12
- userId: z.string().min(1).max(256),
13
- productId: z.string().min(1).max(256),
14
- });
15
- export function createValidateRouter(config, store) {
16
- const router = Router();
17
- router.post(ROUTES.VALIDATE, async (req, res) => {
18
- let platform;
19
- let receipt;
20
- let userId;
21
- let productId;
22
- try {
23
- ({ platform, receipt, userId, productId } = validateSchema.parse(req.body));
24
- }
25
- catch (err) {
26
- if (err instanceof z.ZodError) {
27
- sendZodError(res, err, NO_SUB);
28
- return;
29
- }
30
- throw err;
31
- }
32
- try {
33
- let sub = null;
34
- if (platform === 'apple') {
35
- if (!config.apple) {
36
- sendError(res, 500, ONESUB_ERROR_CODE.APPLE_CONFIG_MISSING, 'Apple configuration not provided', NO_SUB);
37
- return;
38
- }
39
- sub = await validateAppleReceipt(receipt, config.apple);
40
- }
41
- else {
42
- if (!config.google) {
43
- sendError(res, 500, ONESUB_ERROR_CODE.GOOGLE_CONFIG_MISSING, 'Google configuration not provided', NO_SUB);
44
- return;
45
- }
46
- sub = await validateGoogleReceipt(receipt, productId, config.google);
47
- }
48
- if (!sub) {
49
- sendError(res, 422, ONESUB_ERROR_CODE.RECEIPT_VALIDATION_FAILED, 'Receipt validation failed', NO_SUB);
50
- return;
51
- }
52
- sub.userId = userId;
53
- await store.save(sub);
54
- // Google requires acknowledgement within 3 days of purchase or the
55
- // transaction is auto-refunded. Fire-and-forget — entitlement is already
56
- // saved, ack is idempotent on the Play side.
57
- if (platform === 'google' && config.google) {
58
- void acknowledgeGoogleSubscription(receipt, productId, config.google);
59
- }
60
- const response = { valid: true, subscription: sub };
61
- res.status(200).json(response);
62
- }
63
- catch (err) {
64
- log.error('[onesub/validate] Unexpected error:', err);
65
- sendError(res, 500, ONESUB_ERROR_CODE.INTERNAL_ERROR, 'Internal server error during receipt validation', NO_SUB);
66
- }
67
- });
68
- return router;
69
- }
70
- //# sourceMappingURL=validate.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/routes/validate.ts"],"names":[],"mappings":"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"}
@@ -1,145 +0,0 @@
1
- import { SUBSCRIPTION_STATUS, ONESUB_ERROR_CODE } from '@onesub/shared';
2
- import { decodeAppleNotification, decodeJws, sendAppleConsumptionResponse, fetchAppleSubscriptionStatus, } from '../providers/apple.js';
3
- import { log } from '../logger.js';
4
- import { sendError } from '../errors.js';
5
- const APPLE_ACTIVE_TYPES = new Set(['SUBSCRIBED', 'DID_RENEW', 'DID_RECOVER', 'OFFER_REDEEMED']);
6
- const APPLE_CANCELED_TYPES = new Set(['REVOKE', 'REFUND', 'CONSUMPTION_REQUEST']);
7
- const APPLE_EXPIRED_TYPES = new Set(['EXPIRED']);
8
- function mapAppleNotificationStatus(notificationType, subtype) {
9
- if (notificationType === 'DID_FAIL_TO_RENEW') {
10
- return subtype === 'GRACE_PERIOD'
11
- ? SUBSCRIPTION_STATUS.GRACE_PERIOD
12
- : SUBSCRIPTION_STATUS.ON_HOLD;
13
- }
14
- if (notificationType === 'GRACE_PERIOD_EXPIRED')
15
- return SUBSCRIPTION_STATUS.ON_HOLD;
16
- if (APPLE_CANCELED_TYPES.has(notificationType))
17
- return SUBSCRIPTION_STATUS.CANCELED;
18
- if (APPLE_EXPIRED_TYPES.has(notificationType))
19
- return SUBSCRIPTION_STATUS.EXPIRED;
20
- if (APPLE_ACTIVE_TYPES.has(notificationType))
21
- return SUBSCRIPTION_STATUS.ACTIVE;
22
- return null;
23
- }
24
- export async function handleAppleWebhook(req, res, config, store, purchaseStore, webhookEventStore) {
25
- const body = req.body;
26
- if (!body.signedPayload) {
27
- sendError(res, 400, ONESUB_ERROR_CODE.MISSING_SIGNED_PAYLOAD, 'Missing signedPayload');
28
- return;
29
- }
30
- let payload;
31
- try {
32
- payload = await decodeJws(body.signedPayload, config.apple?.skipJwsVerification);
33
- }
34
- catch (err) {
35
- log.error('[onesub/webhook/apple] Failed to decode signedPayload:', err);
36
- sendError(res, 400, ONESUB_ERROR_CODE.INVALID_SIGNED_PAYLOAD, 'Invalid signedPayload');
37
- return;
38
- }
39
- if (webhookEventStore && typeof payload.notificationUUID === 'string') {
40
- const fresh = await webhookEventStore.markIfNew('apple', payload.notificationUUID);
41
- if (!fresh) {
42
- log.info('[onesub/webhook/apple] dedupe: already processed', payload.notificationUUID);
43
- res.status(200).json({ received: true, deduped: true });
44
- return;
45
- }
46
- }
47
- const decoded = await decodeAppleNotification(payload, config.apple?.skipJwsVerification);
48
- if (!decoded) {
49
- res.status(200).json({ received: true });
50
- return;
51
- }
52
- const { originalTransactionId, transactionId, type, productId, bundleId, environment, status, willRenew, expiresAt, appAccountToken, inAppOwnershipType, } = decoded;
53
- const notificationType = payload.notificationType;
54
- const subtype = payload.subtype;
55
- const mapped = mapAppleNotificationStatus(notificationType, subtype);
56
- const finalStatus = mapped ?? status;
57
- if (notificationType === 'CONSUMPTION_REQUEST' &&
58
- config.apple?.consumptionInfoProvider &&
59
- transactionId &&
60
- productId) {
61
- const provider = config.apple.consumptionInfoProvider;
62
- const appleConfig = config.apple;
63
- void (async () => {
64
- try {
65
- const info = await provider({
66
- transactionId,
67
- originalTransactionId,
68
- productId,
69
- bundleId: bundleId ?? appleConfig.bundleId,
70
- environment,
71
- });
72
- if (info) {
73
- await sendAppleConsumptionResponse(transactionId, info, appleConfig, {
74
- sandbox: environment === 'Sandbox',
75
- });
76
- }
77
- }
78
- catch (err) {
79
- log.warn('[onesub/webhook/apple] consumptionInfoProvider failed:', err);
80
- }
81
- })();
82
- }
83
- const isOneTimePurchase = type === 'Consumable' || type === 'Non-Consumable';
84
- const isRefundOrRevoke = APPLE_CANCELED_TYPES.has(notificationType);
85
- try {
86
- if (isOneTimePurchase && isRefundOrRevoke) {
87
- const lookupId = transactionId ?? originalTransactionId;
88
- const removed = await purchaseStore.deletePurchaseByTransactionId(lookupId);
89
- if (!removed) {
90
- log.warn('[onesub/webhook/apple] IAP refund for unknown transaction:', lookupId);
91
- }
92
- res.status(200).json({ received: true });
93
- return;
94
- }
95
- const existing = await store.getByTransactionId(originalTransactionId);
96
- if (existing) {
97
- const isSubscriptionRefund = isRefundOrRevoke && !isOneTimePurchase && notificationType !== 'CONSUMPTION_REQUEST';
98
- const keepEntitlement = isSubscriptionRefund && config.refundPolicy === 'until_expiry';
99
- // If the stored userId was a fallback (originalTransactionId) and we now
100
- // have a real appAccountToken, correct it. Never overwrite a userId that
101
- // the client set explicitly (which would differ from originalTransactionId).
102
- const correctedUserId = appAccountToken && existing.userId === originalTransactionId
103
- ? appAccountToken
104
- : existing.userId;
105
- if (correctedUserId !== existing.userId) {
106
- log.info('[onesub/webhook/apple] correcting userId from originalTransactionId to appAccountToken:', correctedUserId);
107
- }
108
- const updated = keepEntitlement
109
- ? { ...existing, userId: correctedUserId, willRenew: false }
110
- : {
111
- ...existing,
112
- userId: correctedUserId,
113
- status: finalStatus,
114
- willRenew,
115
- expiresAt: expiresAt ?? existing.expiresAt,
116
- };
117
- await store.save(updated);
118
- }
119
- else if (config.apple?.issuerId && config.apple?.keyId && config.apple?.privateKey) {
120
- const fresh = await fetchAppleSubscriptionStatus(originalTransactionId, config.apple, {
121
- sandbox: environment === 'Sandbox',
122
- });
123
- if (fresh) {
124
- fresh.userId = appAccountToken ?? originalTransactionId;
125
- if (inAppOwnershipType === 'FAMILY_SHARED') {
126
- const source = appAccountToken ? 'appAccountToken' : 'originalTransactionId (fallback)';
127
- log.info(`[onesub/webhook/apple] FAMILY_SHARED — userId: ${fresh.userId} (source: ${source})`);
128
- }
129
- await store.save(fresh);
130
- }
131
- else {
132
- log.warn('[onesub/webhook/apple] Unknown transaction and Status API returned no record:', originalTransactionId);
133
- }
134
- }
135
- else {
136
- log.warn('[onesub/webhook/apple] Received notification for unknown transaction (no API creds to recover):', originalTransactionId);
137
- }
138
- res.status(200).json({ received: true });
139
- }
140
- catch (err) {
141
- log.error('[onesub/webhook/apple] Store update error:', err);
142
- sendError(res, 500, ONESUB_ERROR_CODE.WEBHOOK_PROCESSING_FAILED, 'Failed to update subscription');
143
- }
144
- }
145
- //# sourceMappingURL=webhook-apple.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"webhook-apple.js","sourceRoot":"","sources":["../../src/routes/webhook-apple.ts"],"names":[],"mappings":"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"}
@@ -1,204 +0,0 @@
1
- import { createRemoteJWKSet, jwtVerify } from 'jose';
2
- import { SUBSCRIPTION_STATUS, ONESUB_ERROR_CODE } from '@onesub/shared';
3
- import { decodeGoogleNotification, decodeGoogleVoidedNotification, decodeGoogleOneTimeProductNotification, validateGoogleReceipt, acknowledgeGoogleProduct, isGoogleActiveNotification, isGoogleCanceledNotification, isGoogleExpiredNotification, isGoogleGracePeriodNotification, isGoogleOnHoldNotification, isGooglePausedNotification, isGooglePriceChangeConfirmedNotification, } from '../providers/google.js';
4
- import { log } from '../logger.js';
5
- import { sendError } from '../errors.js';
6
- const GOOGLE_JWKS_URL = 'https://www.googleapis.com/oauth2/v3/certs';
7
- let googleJwks = null;
8
- function getGoogleJwks() {
9
- if (!googleJwks)
10
- googleJwks = createRemoteJWKSet(new URL(GOOGLE_JWKS_URL));
11
- return googleJwks;
12
- }
13
- export async function verifyGooglePushToken(req, expectedAudience) {
14
- const authHeader = req.headers['authorization'];
15
- if (typeof authHeader !== 'string' || !authHeader.startsWith('Bearer '))
16
- return false;
17
- try {
18
- await jwtVerify(authHeader.slice('Bearer '.length).trim(), getGoogleJwks(), {
19
- audience: expectedAudience,
20
- });
21
- return true;
22
- }
23
- catch {
24
- return false;
25
- }
26
- }
27
- export async function handleGoogleWebhook(req, res, config, store, purchaseStore, webhookEventStore) {
28
- if (config.google?.pushAudience) {
29
- const authenticated = await verifyGooglePushToken(req, config.google.pushAudience);
30
- if (!authenticated) {
31
- sendError(res, 401, ONESUB_ERROR_CODE.UNAUTHORIZED, 'Unauthorized');
32
- return;
33
- }
34
- }
35
- const body = req.body;
36
- if (!body.message?.data) {
37
- sendError(res, 400, ONESUB_ERROR_CODE.MISSING_MESSAGE_DATA, 'Missing message.data');
38
- return;
39
- }
40
- if (webhookEventStore && typeof body.message.messageId === 'string') {
41
- const fresh = await webhookEventStore.markIfNew('google', body.message.messageId);
42
- if (!fresh) {
43
- log.info('[onesub/webhook/google] dedupe: already processed', body.message.messageId);
44
- res.status(200).json({ received: true, deduped: true });
45
- return;
46
- }
47
- }
48
- const voided = decodeGoogleVoidedNotification(body);
49
- if (voided) {
50
- if (config.google?.packageName && voided.packageName !== config.google.packageName) {
51
- log.warn('[onesub/webhook/google] voided package name mismatch:', voided.packageName, '!==', config.google.packageName);
52
- sendError(res, 400, ONESUB_ERROR_CODE.PACKAGE_NAME_MISMATCH, 'Package name mismatch');
53
- return;
54
- }
55
- try {
56
- if (voided.productType === 1) {
57
- const existing = await store.getByTransactionId(voided.purchaseToken);
58
- if (existing) {
59
- const updated = config.refundPolicy === 'until_expiry'
60
- ? { ...existing, willRenew: false }
61
- : { ...existing, status: SUBSCRIPTION_STATUS.CANCELED };
62
- await store.save(updated);
63
- }
64
- else {
65
- log.warn('[onesub/webhook/google] voided subscription for unknown purchaseToken:', voided.purchaseToken);
66
- }
67
- }
68
- else {
69
- const removed = await purchaseStore.deletePurchaseByTransactionId(voided.orderId);
70
- if (!removed) {
71
- log.warn('[onesub/webhook/google] voided IAP for unknown orderId:', voided.orderId);
72
- }
73
- }
74
- res.status(200).json({ received: true });
75
- }
76
- catch (err) {
77
- log.error('[onesub/webhook/google] voided notification error:', err);
78
- sendError(res, 500, ONESUB_ERROR_CODE.WEBHOOK_PROCESSING_FAILED, 'Failed to process voided notification');
79
- }
80
- return;
81
- }
82
- // oneTimeProductNotification — consumable / non-consumable purchase signal.
83
- // The notification carries no userId, so we cannot create a purchase record
84
- // here (the client's POST /onesub/purchase/validate is the authoritative path).
85
- // For PURCHASED we acknowledge to prevent the 3-day auto-refund window.
86
- const oneTimeProduct = decodeGoogleOneTimeProductNotification(body);
87
- if (oneTimeProduct) {
88
- if (config.google?.packageName && oneTimeProduct.packageName !== config.google.packageName) {
89
- log.warn('[onesub/webhook/google] oneTimeProduct package name mismatch:', oneTimeProduct.packageName, '!==', config.google.packageName);
90
- sendError(res, 400, ONESUB_ERROR_CODE.PACKAGE_NAME_MISMATCH, 'Package name mismatch');
91
- return;
92
- }
93
- try {
94
- const { notificationType, purchaseToken, sku } = oneTimeProduct;
95
- if (notificationType === 1 /* PURCHASED */) {
96
- log.info('[onesub/webhook/google] oneTimeProduct PURCHASED:', sku);
97
- if (config.google?.serviceAccountKey && config.google.packageName) {
98
- void acknowledgeGoogleProduct(purchaseToken, sku, config.google).catch((err) => log.warn(`[onesub/webhook/google] oneTimeProduct ack failed for SKU ${sku} — 3-day auto-refund risk:`, err));
99
- }
100
- }
101
- else {
102
- // notificationType === 2: CANCELED (user aborted before purchase completed)
103
- log.info('[onesub/webhook/google] oneTimeProduct CANCELED (pre-completion):', sku);
104
- }
105
- res.status(200).json({ received: true });
106
- }
107
- catch (err) {
108
- log.error('[onesub/webhook/google] oneTimeProduct error:', err);
109
- sendError(res, 500, ONESUB_ERROR_CODE.WEBHOOK_PROCESSING_FAILED, 'Failed to process oneTimeProduct notification');
110
- }
111
- return;
112
- }
113
- const notification = decodeGoogleNotification(body);
114
- if (!notification) {
115
- res.status(200).json({ received: true });
116
- return;
117
- }
118
- const { notificationType, purchaseToken, subscriptionId, packageName } = notification;
119
- if (config.google?.packageName && packageName !== config.google.packageName) {
120
- log.warn('[onesub/webhook/google] Package name mismatch:', packageName, '!==', config.google.packageName);
121
- sendError(res, 400, ONESUB_ERROR_CODE.PACKAGE_NAME_MISMATCH, 'Package name mismatch');
122
- return;
123
- }
124
- try {
125
- const existing = await store.getByTransactionId(purchaseToken);
126
- let finalStatus;
127
- if (isGoogleActiveNotification(notificationType)) {
128
- finalStatus = SUBSCRIPTION_STATUS.ACTIVE;
129
- }
130
- else if (isGoogleGracePeriodNotification(notificationType)) {
131
- finalStatus = SUBSCRIPTION_STATUS.GRACE_PERIOD;
132
- }
133
- else if (isGoogleOnHoldNotification(notificationType)) {
134
- finalStatus = SUBSCRIPTION_STATUS.ON_HOLD;
135
- }
136
- else if (isGooglePausedNotification(notificationType)) {
137
- finalStatus = SUBSCRIPTION_STATUS.PAUSED;
138
- }
139
- else if (isGooglePriceChangeConfirmedNotification(notificationType)) {
140
- finalStatus = SUBSCRIPTION_STATUS.ACTIVE;
141
- }
142
- else if (isGoogleCanceledNotification(notificationType)) {
143
- finalStatus = SUBSCRIPTION_STATUS.CANCELED;
144
- }
145
- else if (isGoogleExpiredNotification(notificationType)) {
146
- finalStatus = SUBSCRIPTION_STATUS.EXPIRED;
147
- }
148
- else {
149
- finalStatus = SUBSCRIPTION_STATUS.ACTIVE;
150
- }
151
- if (isGooglePriceChangeConfirmedNotification(notificationType) && config.google?.onPriceChangeConfirmed) {
152
- const hook = config.google.onPriceChangeConfirmed;
153
- void Promise.resolve()
154
- .then(() => hook({ purchaseToken, subscriptionId, packageName }))
155
- .catch((err) => log.warn('[onesub/webhook/google] onPriceChangeConfirmed hook failed:', err));
156
- }
157
- if (existing) {
158
- let updated = { ...existing, status: finalStatus };
159
- if (config.google?.serviceAccountKey) {
160
- const fresh = await validateGoogleReceipt(purchaseToken, subscriptionId, config.google);
161
- if (fresh) {
162
- const preserveNotificationStatus = finalStatus === SUBSCRIPTION_STATUS.GRACE_PERIOD ||
163
- finalStatus === SUBSCRIPTION_STATUS.ON_HOLD;
164
- updated = {
165
- ...existing,
166
- status: preserveNotificationStatus ? finalStatus : fresh.status,
167
- expiresAt: fresh.expiresAt,
168
- willRenew: fresh.willRenew,
169
- autoResumeTime: fresh.autoResumeTime,
170
- linkedPurchaseToken: fresh.linkedPurchaseToken ?? existing.linkedPurchaseToken,
171
- };
172
- }
173
- }
174
- await store.save(updated);
175
- }
176
- else {
177
- if (config.google?.serviceAccountKey) {
178
- const fresh = await validateGoogleReceipt(purchaseToken, subscriptionId, config.google);
179
- if (fresh) {
180
- if (fresh.linkedPurchaseToken) {
181
- const previous = await store.getByTransactionId(fresh.linkedPurchaseToken);
182
- fresh.userId = previous ? previous.userId : purchaseToken;
183
- if (previous) {
184
- log.info(`[onesub/webhook/google] inherited userId ${previous.userId} from linkedPurchaseToken ${fresh.linkedPurchaseToken} → new token ${purchaseToken}`);
185
- }
186
- }
187
- else {
188
- fresh.userId = purchaseToken;
189
- }
190
- await store.save(fresh);
191
- }
192
- }
193
- else {
194
- log.warn('[onesub/webhook/google] Unknown purchase token and no serviceAccountKey to re-fetch:', purchaseToken);
195
- }
196
- }
197
- res.status(200).json({ received: true });
198
- }
199
- catch (err) {
200
- log.error('[onesub/webhook/google] Error handling notification:', err);
201
- sendError(res, 500, ONESUB_ERROR_CODE.WEBHOOK_PROCESSING_FAILED, 'Failed to process notification');
202
- }
203
- }
204
- //# sourceMappingURL=webhook-google.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"webhook-google.js","sourceRoot":"","sources":["../../src/routes/webhook-google.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AAGrD,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExE,OAAO,EACL,wBAAwB,EACxB,8BAA8B,EAC9B,sCAAsC,EACtC,qBAAqB,EACrB,wBAAwB,EACxB,0BAA0B,EAC1B,4BAA4B,EAC5B,2BAA2B,EAC3B,+BAA+B,EAC/B,0BAA0B,EAC1B,0BAA0B,EAC1B,wCAAwC,GACzC,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGzC,MAAM,eAAe,GAAG,4CAA4C,CAAC;AAErE,IAAI,UAAU,GAAiD,IAAI,CAAC;AAEpE,SAAS,aAAa;IACpB,IAAI,CAAC,UAAU;QAAE,UAAU,GAAG,kBAAkB,CAAC,IAAI,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC;IAC3E,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,GAAY,EAAE,gBAAwB;IAChF,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IAChD,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,KAAK,CAAC;IACtF,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,EAAE;YAC1E,QAAQ,EAAE,gBAAgB;SAC3B,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,GAAY,EACZ,GAAa,EACb,MAA0B,EAC1B,KAAwB,EACxB,aAA4B,EAC5B,iBAAqC;IAErC,IAAI,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC;QAChC,MAAM,aAAa,GAAG,MAAM,qBAAqB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;QACnF,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;YACpE,OAAO;QACT,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GAAG,GAAG,CAAC,IAA0C,CAAC;IAE5D,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;QACxB,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,CAAC,oBAAoB,EAAE,sBAAsB,CAAC,CAAC;QACpF,OAAO;IACT,CAAC;IAED,IAAI,iBAAiB,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;QACpE,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAClF,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,GAAG,CAAC,IAAI,CAAC,mDAAmD,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YACtF,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;YACxD,OAAO;QACT,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,8BAA8B,CAAC,IAAiC,CAAC,CAAC;IACjF,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,IAAI,MAAM,CAAC,WAAW,KAAK,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YACnF,GAAG,CAAC,IAAI,CAAC,uDAAuD,EAAE,MAAM,CAAC,WAAW,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YACxH,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,CAAC,qBAAqB,EAAE,uBAAuB,CAAC,CAAC;YACtF,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,IAAI,MAAM,CAAC,WAAW,KAAK,CAAC,EAAE,CAAC;gBAC7B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,kBAAkB,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;gBACtE,IAAI,QAAQ,EAAE,CAAC;oBACb,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,KAAK,cAAc;wBACpD,CAAC,CAAC,EAAE,GAAG,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE;wBACnC,CAAC,CAAC,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,mBAAmB,CAAC,QAAQ,EAAE,CAAC;oBAC1D,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAC5B,CAAC;qBAAM,CAAC;oBACN,GAAG,CAAC,IAAI,CAAC,wEAAwE,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;gBAC3G,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,6BAA6B,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBAClF,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,GAAG,CAAC,IAAI,CAAC,yDAAyD,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;gBACtF,CAAC;YACH,CAAC;YACD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,oDAAoD,EAAE,GAAG,CAAC,CAAC;YACrE,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,CAAC,yBAAyB,EAAE,uCAAuC,CAAC,CAAC;QAC5G,CAAC;QACD,OAAO;IACT,CAAC;IAED,4EAA4E;IAC5E,4EAA4E;IAC5E,gFAAgF;IAChF,wEAAwE;IACxE,MAAM,cAAc,GAAG,sCAAsC,CAAC,IAAiC,CAAC,CAAC;IACjG,IAAI,cAAc,EAAE,CAAC;QACnB,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,IAAI,cAAc,CAAC,WAAW,KAAK,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YAC3F,GAAG,CAAC,IAAI,CAAC,+DAA+D,EAAE,cAAc,CAAC,WAAW,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YACxI,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,CAAC,qBAAqB,EAAE,uBAAuB,CAAC,CAAC;YACtF,OAAO;QACT,CAAC;QACD,IAAI,CAAC;YACH,MAAM,EAAE,gBAAgB,EAAE,aAAa,EAAE,GAAG,EAAE,GAAG,cAAc,CAAC;YAChE,IAAI,gBAAgB,KAAK,CAAC,CAAC,eAAe,EAAE,CAAC;gBAC3C,GAAG,CAAC,IAAI,CAAC,mDAAmD,EAAE,GAAG,CAAC,CAAC;gBACnE,IAAI,MAAM,CAAC,MAAM,EAAE,iBAAiB,IAAI,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;oBAClE,KAAK,wBAAwB,CAAC,aAAa,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,CACpE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,6DAA6D,GAAG,4BAA4B,EAAE,GAAG,CAAC,CACrH,CAAC;gBACJ,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,4EAA4E;gBAC5E,GAAG,CAAC,IAAI,CAAC,mEAAmE,EAAE,GAAG,CAAC,CAAC;YACrF,CAAC;YACD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,+CAA+C,EAAE,GAAG,CAAC,CAAC;YAChE,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,CAAC,yBAAyB,EAAE,+CAA+C,CAAC,CAAC;QACpH,CAAC;QACD,OAAO;IACT,CAAC;IAED,MAAM,YAAY,GAAG,wBAAwB,CAAC,IAAiC,CAAC,CAAC;IACjF,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACzC,OAAO;IACT,CAAC;IAED,MAAM,EAAE,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,GAAG,YAAY,CAAC;IAEtF,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,IAAI,WAAW,KAAK,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QAC5E,GAAG,CAAC,IAAI,CAAC,gDAAgD,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAC1G,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,CAAC,qBAAqB,EAAE,uBAAuB,CAAC,CAAC;QACtF,OAAO;IACT,CAAC;IAED,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC;QAE/D,IAAI,WAAuC,CAAC;QAC5C,IAAI,0BAA0B,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACjD,WAAW,GAAG,mBAAmB,CAAC,MAAM,CAAC;QAC3C,CAAC;aAAM,IAAI,+BAA+B,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAC7D,WAAW,GAAG,mBAAmB,CAAC,YAAY,CAAC;QACjD,CAAC;aAAM,IAAI,0BAA0B,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACxD,WAAW,GAAG,mBAAmB,CAAC,OAAO,CAAC;QAC5C,CAAC;aAAM,IAAI,0BAA0B,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACxD,WAAW,GAAG,mBAAmB,CAAC,MAAM,CAAC;QAC3C,CAAC;aAAM,IAAI,wCAAwC,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACtE,WAAW,GAAG,mBAAmB,CAAC,MAAM,CAAC;QAC3C,CAAC;aAAM,IAAI,4BAA4B,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAC1D,WAAW,GAAG,mBAAmB,CAAC,QAAQ,CAAC;QAC7C,CAAC;aAAM,IAAI,2BAA2B,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACzD,WAAW,GAAG,mBAAmB,CAAC,OAAO,CAAC;QAC5C,CAAC;aAAM,CAAC;YACN,WAAW,GAAG,mBAAmB,CAAC,MAAM,CAAC;QAC3C,CAAC;QAED,IAAI,wCAAwC,CAAC,gBAAgB,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,sBAAsB,EAAE,CAAC;YACxG,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC;YAClD,KAAK,OAAO,CAAC,OAAO,EAAE;iBACnB,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC,CAAC;iBAChE,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,6DAA6D,EAAE,GAAG,CAAC,CAAC,CAAC;QAClG,CAAC;QAED,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,OAAO,GAAqB,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;YAErE,IAAI,MAAM,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC;gBACrC,MAAM,KAAK,GAAG,MAAM,qBAAqB,CAAC,aAAa,EAAE,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;gBACxF,IAAI,KAAK,EAAE,CAAC;oBACV,MAAM,0BAA0B,GAC9B,WAAW,KAAK,mBAAmB,CAAC,YAAY;wBAChD,WAAW,KAAK,mBAAmB,CAAC,OAAO,CAAC;oBAC9C,OAAO,GAAG;wBACR,GAAG,QAAQ;wBACX,MAAM,EAAE,0BAA0B,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM;wBAC/D,SAAS,EAAE,KAAK,CAAC,SAAS;wBAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;wBAC1B,cAAc,EAAE,KAAK,CAAC,cAAc;wBACpC,mBAAmB,EAAE,KAAK,CAAC,mBAAmB,IAAI,QAAQ,CAAC,mBAAmB;qBAC/E,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC5B,CAAC;aAAM,CAAC;YACN,IAAI,MAAM,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC;gBACrC,MAAM,KAAK,GAAG,MAAM,qBAAqB,CAAC,aAAa,EAAE,cAAc,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;gBACxF,IAAI,KAAK,EAAE,CAAC;oBACV,IAAI,KAAK,CAAC,mBAAmB,EAAE,CAAC;wBAC9B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,kBAAkB,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;wBAC3E,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC;wBAC1D,IAAI,QAAQ,EAAE,CAAC;4BACb,GAAG,CAAC,IAAI,CAAC,4CAA4C,QAAQ,CAAC,MAAM,6BAA6B,KAAK,CAAC,mBAAmB,gBAAgB,aAAa,EAAE,CAAC,CAAC;wBAC7J,CAAC;oBACH,CAAC;yBAAM,CAAC;wBACN,KAAK,CAAC,MAAM,GAAG,aAAa,CAAC;oBAC/B,CAAC;oBACD,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC1B,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,GAAG,CAAC,IAAI,CAAC,sFAAsF,EAAE,aAAa,CAAC,CAAC;YAClH,CAAC;QACH,CAAC;QAED,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,KAAK,CAAC,sDAAsD,EAAE,GAAG,CAAC,CAAC;QACvE,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,iBAAiB,CAAC,yBAAyB,EAAE,gCAAgC,CAAC,CAAC;IACrG,CAAC;AACH,CAAC"}
@@ -1,19 +0,0 @@
1
- import { Router } from 'express';
2
- import { ROUTES } from '@onesub/shared';
3
- import { handleAppleWebhook } from './webhook-apple.js';
4
- import { handleGoogleWebhook } from './webhook-google.js';
5
- /**
6
- * Retry / durability semantics.
7
- *
8
- * Both Apple and Google retry on any non-2xx response.
9
- * 4xx — payload is unusable; do NOT retry.
10
- * 5xx — transient failure; source will retry.
11
- * 2xx — processed or intentionally ignored.
12
- */
13
- export function createWebhookRouter(config, store, purchaseStore, webhookEventStore) {
14
- const router = Router();
15
- router.post(ROUTES.WEBHOOK_APPLE, (req, res) => handleAppleWebhook(req, res, config, store, purchaseStore, webhookEventStore));
16
- router.post(ROUTES.WEBHOOK_GOOGLE, (req, res) => handleGoogleWebhook(req, res, config, store, purchaseStore, webhookEventStore));
17
- return router;
18
- }
19
- //# sourceMappingURL=webhook.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"webhook.js","sourceRoot":"","sources":["../../src/routes/webhook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAGjC,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAGxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAA0B,EAC1B,KAAwB,EACxB,aAA4B,EAC5B,iBAAqC;IAErC,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IAExB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE,CAChE,kBAAkB,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,iBAAiB,CAAC,CAC9E,CAAC;IAEF,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE,CACjE,mBAAmB,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,iBAAiB,CAAC,CAC/E,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/dist/store.js DELETED
@@ -1,145 +0,0 @@
1
- /**
2
- * In-memory implementation — suitable for development and testing.
3
- * Data is lost on process restart.
4
- */
5
- export class InMemorySubscriptionStore {
6
- // Multiple records per user (different originalTransactionIds) — required
7
- // for entitlement evaluation across multiple productIds. Ordering is
8
- // last-written-first so getByUserId returns "most recent" naturally.
9
- byUserId = new Map();
10
- byTransactionId = new Map();
11
- async save(sub) {
12
- this.byTransactionId.set(sub.originalTransactionId, sub);
13
- const existing = this.byUserId.get(sub.userId) ?? [];
14
- // Replace any prior record with the same originalTransactionId, then
15
- // unshift to the front so the latest write is index 0 (= getByUserId result).
16
- const filtered = existing.filter((s) => s.originalTransactionId !== sub.originalTransactionId);
17
- filtered.unshift(sub);
18
- this.byUserId.set(sub.userId, filtered);
19
- }
20
- async getByUserId(userId) {
21
- const list = this.byUserId.get(userId);
22
- return list?.[0] ?? null;
23
- }
24
- async getAllByUserId(userId) {
25
- return [...(this.byUserId.get(userId) ?? [])];
26
- }
27
- async getByTransactionId(txId) {
28
- return this.byTransactionId.get(txId) ?? null;
29
- }
30
- async listAll() {
31
- return [...this.byTransactionId.values()];
32
- }
33
- async listFiltered(opts) {
34
- const limit = opts.limit ?? 50;
35
- const offset = opts.offset ?? 0;
36
- // Iterate via byUserId so insertion-order is "newest first" within each
37
- // user (matches PostgresStore's `updated_at DESC` semantic). Across users
38
- // we collect in Map iteration order — stable for a given run.
39
- const all = [];
40
- for (const list of this.byUserId.values()) {
41
- for (const s of list)
42
- all.push(s);
43
- }
44
- const filtered = all.filter((s) => {
45
- if (opts.userId && s.userId !== opts.userId)
46
- return false;
47
- if (opts.status && s.status !== opts.status)
48
- return false;
49
- if (opts.productId && s.productId !== opts.productId)
50
- return false;
51
- if (opts.platform && s.platform !== opts.platform)
52
- return false;
53
- return true;
54
- });
55
- return {
56
- items: filtered.slice(offset, offset + limit),
57
- total: filtered.length,
58
- limit,
59
- offset,
60
- };
61
- }
62
- }
63
- /**
64
- * In-memory implementation of PurchaseStore — suitable for development and testing.
65
- * Data is lost on process restart.
66
- */
67
- export class InMemoryPurchaseStore {
68
- byTransactionId = new Map();
69
- byUserId = new Map();
70
- async savePurchase(purchase) {
71
- const existing = this.byTransactionId.get(purchase.transactionId);
72
- if (existing) {
73
- if (existing.userId !== purchase.userId) {
74
- const err = new Error('TRANSACTION_BELONGS_TO_OTHER_USER');
75
- err.code = 'TRANSACTION_BELONGS_TO_OTHER_USER';
76
- throw err;
77
- }
78
- return; // same user — idempotent
79
- }
80
- this.byTransactionId.set(purchase.transactionId, purchase);
81
- const list = this.byUserId.get(purchase.userId) ?? [];
82
- list.push(purchase);
83
- this.byUserId.set(purchase.userId, list);
84
- }
85
- async getPurchasesByUserId(userId) {
86
- return this.byUserId.get(userId) ?? [];
87
- }
88
- async getPurchaseByTransactionId(txId) {
89
- return this.byTransactionId.get(txId) ?? null;
90
- }
91
- async hasPurchased(userId, productId) {
92
- const purchases = this.byUserId.get(userId);
93
- if (!purchases)
94
- return false;
95
- return purchases.some((p) => p.productId === productId);
96
- }
97
- async reassignPurchase(transactionId, newUserId) {
98
- const existing = this.byTransactionId.get(transactionId);
99
- if (!existing)
100
- return false;
101
- const oldUserId = existing.userId;
102
- if (oldUserId === newUserId)
103
- return true;
104
- const updated = { ...existing, userId: newUserId };
105
- this.byTransactionId.set(transactionId, updated);
106
- // remove from old userId index
107
- const oldList = (this.byUserId.get(oldUserId) ?? []).filter((p) => p.transactionId !== transactionId);
108
- if (oldList.length)
109
- this.byUserId.set(oldUserId, oldList);
110
- else
111
- this.byUserId.delete(oldUserId);
112
- // add to new userId index
113
- const newList = this.byUserId.get(newUserId) ?? [];
114
- newList.push(updated);
115
- this.byUserId.set(newUserId, newList);
116
- return true;
117
- }
118
- async deletePurchases(userId, productId) {
119
- const list = this.byUserId.get(userId) ?? [];
120
- const kept = list.filter((p) => p.productId !== productId);
121
- const deleted = list.length - kept.length;
122
- this.byUserId.set(userId, kept);
123
- for (const p of list) {
124
- if (p.productId === productId)
125
- this.byTransactionId.delete(p.transactionId);
126
- }
127
- return deleted;
128
- }
129
- async listAll() {
130
- return [...this.byTransactionId.values()];
131
- }
132
- async deletePurchaseByTransactionId(transactionId) {
133
- const existing = this.byTransactionId.get(transactionId);
134
- if (!existing)
135
- return false;
136
- this.byTransactionId.delete(transactionId);
137
- const list = (this.byUserId.get(existing.userId) ?? []).filter((p) => p.transactionId !== transactionId);
138
- if (list.length)
139
- this.byUserId.set(existing.userId, list);
140
- else
141
- this.byUserId.delete(existing.userId);
142
- return true;
143
- }
144
- }
145
- //# sourceMappingURL=store.js.map
package/dist/store.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}