iap-apple 1.3.3 → 1.3.5

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.
File without changes
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./internal"), exports);
18
+ __exportStar(require("./shared"), exports);
@@ -0,0 +1,4 @@
1
+ import { RECEIPT_STATUS_ENUM } from '../shared';
2
+ export declare const STATUS_TO_MESSAGE_MAP: Record<RECEIPT_STATUS_ENUM, string>;
3
+ export declare const PROD_PATH = "https://buy.itunes.apple.com/verifyReceipt";
4
+ export declare const SANDBOX_PATH = "https://sandbox.itunes.apple.com/verifyReceipt";
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SANDBOX_PATH = exports.PROD_PATH = exports.STATUS_TO_MESSAGE_MAP = void 0;
4
+ exports.STATUS_TO_MESSAGE_MAP = {
5
+ 21000: 'The App Store could not read the JSON object you provided.',
6
+ 21002: 'The data in the receipt-data property was malformed.',
7
+ 21003: 'The receipt could not be authenticated.',
8
+ 21004: 'The shared secret you provided does not match the shared secret on file for your account.',
9
+ 21005: 'The receipt server is not currently available.',
10
+ 21006: 'This receipt is valid but the subscription has expired. When this status code is returned to your server, the receipt data is also decoded and returned as part of the response.',
11
+ 21007: 'This receipt is a sandbox receipt, but it was sent to the production service for verification.',
12
+ 21008: 'This receipt is a production receipt, but it was sent to the sandbox service for verification.',
13
+ 21009: 'Internal data access error. Try again later',
14
+ 21010: 'The user account cannot be found or has been deleted',
15
+ 2: 'The receipt is valid, but purchased nothing.',
16
+ 0: 'No error.',
17
+ };
18
+ exports.PROD_PATH = 'https://buy.itunes.apple.com/verifyReceipt';
19
+ exports.SANDBOX_PATH = 'https://sandbox.itunes.apple.com/verifyReceipt';
@@ -0,0 +1,14 @@
1
+ export declare enum RECEIPT_STATUS_ENUM {
2
+ SUCCESS = 0,
3
+ VALID_NO_PURCHASE = 2,
4
+ CANNOT_READ_JSON = 21000,
5
+ DATA_MALFORMED = 21002,
6
+ RECEIPT_NOT_AUTHENTICATED = 21003,
7
+ SHARED_SECRET_DOESNT_MATCH = 21004,
8
+ SERVER_NOT_AVAILABLE = 21005,
9
+ SUBSCRIPTION_EXPIRED = 21006,
10
+ TEST_ENV_RECEIPT_DETECTED = 21007,
11
+ PRODUCTION_ENV_RECEIPT_DETECTED = 21008,
12
+ INTERNAL_DATA_ACCESS_ERROR = 21009,
13
+ USER_ACCOUNT_DELETED = 21010
14
+ }
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RECEIPT_STATUS_ENUM = void 0;
4
+ var RECEIPT_STATUS_ENUM;
5
+ (function (RECEIPT_STATUS_ENUM) {
6
+ RECEIPT_STATUS_ENUM[RECEIPT_STATUS_ENUM["SUCCESS"] = 0] = "SUCCESS";
7
+ // 'The receipt is valid, but purchased nothing.'
8
+ RECEIPT_STATUS_ENUM[RECEIPT_STATUS_ENUM["VALID_NO_PURCHASE"] = 2] = "VALID_NO_PURCHASE";
9
+ // 'The App Store could not read the JSON object you provided.',
10
+ RECEIPT_STATUS_ENUM[RECEIPT_STATUS_ENUM["CANNOT_READ_JSON"] = 21000] = "CANNOT_READ_JSON";
11
+ // 'The data in the receipt-data property was malformed.',
12
+ RECEIPT_STATUS_ENUM[RECEIPT_STATUS_ENUM["DATA_MALFORMED"] = 21002] = "DATA_MALFORMED";
13
+ // 'The receipt could not be authenticated.',
14
+ RECEIPT_STATUS_ENUM[RECEIPT_STATUS_ENUM["RECEIPT_NOT_AUTHENTICATED"] = 21003] = "RECEIPT_NOT_AUTHENTICATED";
15
+ // The shared secret you provided does not match the shared secret on file for your account.
16
+ RECEIPT_STATUS_ENUM[RECEIPT_STATUS_ENUM["SHARED_SECRET_DOESNT_MATCH"] = 21004] = "SHARED_SECRET_DOESNT_MATCH";
17
+ // 'The receipt server is not currently available.',
18
+ RECEIPT_STATUS_ENUM[RECEIPT_STATUS_ENUM["SERVER_NOT_AVAILABLE"] = 21005] = "SERVER_NOT_AVAILABLE";
19
+ // 'This receipt is valid but the subscription has expired.
20
+ // When this status code is returned to your server, the receipt data is
21
+ // also decoded and returned as part of the response.',
22
+ RECEIPT_STATUS_ENUM[RECEIPT_STATUS_ENUM["SUBSCRIPTION_EXPIRED"] = 21006] = "SUBSCRIPTION_EXPIRED";
23
+ // 'This receipt is a sandbox receipt, but it was sent to the production service for verification.'
24
+ RECEIPT_STATUS_ENUM[RECEIPT_STATUS_ENUM["TEST_ENV_RECEIPT_DETECTED"] = 21007] = "TEST_ENV_RECEIPT_DETECTED";
25
+ // 'This receipt is a production receipt, but it was sent to the sandbox service for verification.'
26
+ RECEIPT_STATUS_ENUM[RECEIPT_STATUS_ENUM["PRODUCTION_ENV_RECEIPT_DETECTED"] = 21008] = "PRODUCTION_ENV_RECEIPT_DETECTED";
27
+ // 'Internal data access error. Try again later'
28
+ RECEIPT_STATUS_ENUM[RECEIPT_STATUS_ENUM["INTERNAL_DATA_ACCESS_ERROR"] = 21009] = "INTERNAL_DATA_ACCESS_ERROR";
29
+ // 'The user account cannot be found or has been deleted'
30
+ RECEIPT_STATUS_ENUM[RECEIPT_STATUS_ENUM["USER_ACCOUNT_DELETED"] = 21010] = "USER_ACCOUNT_DELETED";
31
+ })(RECEIPT_STATUS_ENUM = exports.RECEIPT_STATUS_ENUM || (exports.RECEIPT_STATUS_ENUM = {}));
File without changes
package/index.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./constants/shared"), exports);
18
+ __exportStar(require("./lib/shared"), exports);
19
+ __exportStar(require("./types/shared"), exports);
@@ -0,0 +1,22 @@
1
+ import { ILogger, IReceiptInAppItem, IReceiptValidationResponseBody } from '../../types';
2
+ export declare function isExpiredAppleResponse(responseData: IReceiptValidationResponseBody): boolean;
3
+ export declare function getPurchaseItem(item: IReceiptInAppItem, purchase: IReceiptValidationResponseBody): {
4
+ quantity: number;
5
+ productId: string;
6
+ transactionId: string;
7
+ originalTransactionId: string;
8
+ bundleId: string;
9
+ appItemId: string;
10
+ originalPurchaseDate: number;
11
+ purchaseDateMS: number;
12
+ cancellationDateMS: number | undefined;
13
+ isTrialPeriod: boolean;
14
+ expirationDateMS: number | undefined;
15
+ };
16
+ export declare const validateReceipt: ({ logger, validationEndpoint, receipt, password, excludeOldTransactions, }: {
17
+ logger?: ILogger | null | undefined;
18
+ validationEndpoint: string;
19
+ receipt: string;
20
+ password: string | undefined;
21
+ excludeOldTransactions: boolean;
22
+ }) => Promise<IReceiptValidationResponseBody | null>;
@@ -0,0 +1,182 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (_) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.validateReceipt = exports.getPurchaseItem = exports.isExpiredAppleResponse = void 0;
51
+ var constants_1 = require("../../constants");
52
+ var request = require("superagent");
53
+ function isExpiredAppleResponse(responseData) {
54
+ var date = Math.max.apply(Math, (responseData.latest_receipt_info || [])
55
+ .filter(function (lri) { return lri.expires_date_ms; })
56
+ .map(function (lri) { return parseInt(lri.expires_date_ms, 10); }));
57
+ if (date) {
58
+ return date > Date.now();
59
+ }
60
+ // old receipt
61
+ return false;
62
+ }
63
+ exports.isExpiredAppleResponse = isExpiredAppleResponse;
64
+ function sendRequest(url, content) {
65
+ return __awaiter(this, void 0, void 0, function () {
66
+ return __generator(this, function (_a) {
67
+ return [2 /*return*/, new Promise(function (resolve, reject) {
68
+ try {
69
+ request
70
+ .post(url)
71
+ .set('Content-type', 'application/json')
72
+ .send(JSON.stringify(content))
73
+ .end(function (error, response) {
74
+ if (error || response.status !== 200) {
75
+ reject(error);
76
+ return;
77
+ }
78
+ resolve(response.body);
79
+ });
80
+ }
81
+ catch (err) {
82
+ reject(err);
83
+ }
84
+ })];
85
+ });
86
+ });
87
+ }
88
+ function getPurchaseItem(item, purchase) {
89
+ return {
90
+ quantity: parseInt(item.quantity, 10),
91
+ productId: item.product_id,
92
+ transactionId: item.transaction_id,
93
+ originalTransactionId: item.original_transaction_id,
94
+ bundleId: purchase.receipt.bundle_id,
95
+ appItemId: item.app_item_id,
96
+ originalPurchaseDate: parseInt(item.original_purchase_date_ms, 10),
97
+ purchaseDateMS: parseInt(item.purchase_date_ms, 10),
98
+ cancellationDateMS: item.cancellation_date_ms ? parseInt(item.cancellation_date_ms, 10) : undefined,
99
+ isTrialPeriod: item.is_trial_period === 'true',
100
+ expirationDateMS: item.expires_date_ms ? parseInt(item.expires_date_ms, 10) : undefined,
101
+ };
102
+ }
103
+ exports.getPurchaseItem = getPurchaseItem;
104
+ var validateReceipt = function (_a) {
105
+ var logger = _a.logger, validationEndpoint = _a.validationEndpoint, receipt = _a.receipt, password = _a.password, excludeOldTransactions = _a.excludeOldTransactions;
106
+ return __awaiter(this, void 0, void 0, function () {
107
+ var _this = this;
108
+ return __generator(this, function (_b) {
109
+ return [2 /*return*/, new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
110
+ var content, data, error_1;
111
+ return __generator(this, function (_a) {
112
+ switch (_a.label) {
113
+ case 0:
114
+ content = {
115
+ 'receipt-data': receipt,
116
+ password: password,
117
+ 'exclude-old-transactions': excludeOldTransactions,
118
+ };
119
+ logger === null || logger === void 0 ? void 0 : logger.log("[iap-apple] Validating against: ".concat(validationEndpoint, " endpoint"));
120
+ logger === null || logger === void 0 ? void 0 : logger.log("[iap-apple] Validation data: ".concat(JSON.stringify(content, null, 2)));
121
+ _a.label = 1;
122
+ case 1:
123
+ _a.trys.push([1, 3, , 4]);
124
+ return [4 /*yield*/, sendRequest(validationEndpoint, content)];
125
+ case 2:
126
+ data = _a.sent();
127
+ logger === null || logger === void 0 ? void 0 : logger.log("[iap-apple] Endpoint ".concat(validationEndpoint, " response: ").concat(JSON.stringify(data, null, 2)));
128
+ // apple responded with error
129
+ if (data.status !== constants_1.RECEIPT_STATUS_ENUM.SUCCESS &&
130
+ data.status !== constants_1.RECEIPT_STATUS_ENUM.TEST_ENV_RECEIPT_DETECTED &&
131
+ data.status !== constants_1.RECEIPT_STATUS_ENUM.DATA_MALFORMED) {
132
+ if (data.status === constants_1.RECEIPT_STATUS_ENUM.SUBSCRIPTION_EXPIRED && !isExpiredAppleResponse(data)) {
133
+ /*
134
+ detected valid subscription receipt,
135
+ however it was cancelled, and it has not been expired
136
+ status code is 21006 for both expired receipt and cancelled receipt...
137
+ */
138
+ logger === null || logger === void 0 ? void 0 : logger.log('[iap-apple] Valid receipt, but has been cancelled (not expired yet)');
139
+ // force status to be SUCCESS
140
+ resolve(__assign(__assign({}, data), { status: constants_1.RECEIPT_STATUS_ENUM.SUCCESS }));
141
+ return [2 /*return*/];
142
+ }
143
+ logger === null || logger === void 0 ? void 0 : logger.error("[iap-apple] Endpoint ".concat(validationEndpoint, " failed: ").concat(JSON.stringify(data, null, 2)));
144
+ reject({
145
+ rejectionMessage: constants_1.STATUS_TO_MESSAGE_MAP[data.status] || 'Unknown',
146
+ data: data,
147
+ });
148
+ return [2 /*return*/];
149
+ }
150
+ // try another environment...
151
+ if (data.status === constants_1.RECEIPT_STATUS_ENUM.TEST_ENV_RECEIPT_DETECTED) {
152
+ resolve(null);
153
+ return [2 /*return*/];
154
+ }
155
+ if (data.status === constants_1.RECEIPT_STATUS_ENUM.DATA_MALFORMED) {
156
+ reject({
157
+ rejectionMessage: constants_1.STATUS_TO_MESSAGE_MAP[data.status] || 'Unknown',
158
+ data: data,
159
+ });
160
+ return [2 /*return*/];
161
+ }
162
+ // receipt validated
163
+ logger === null || logger === void 0 ? void 0 : logger.log("[iap-apple] Validation successful: ".concat(JSON.stringify(data, null, 2)));
164
+ resolve(data);
165
+ return [3 /*break*/, 4];
166
+ case 3:
167
+ error_1 = _a.sent();
168
+ logger === null || logger === void 0 ? void 0 : logger.error("[iap-apple] Endpoint ".concat(validationEndpoint, " failed: ").concat(error_1));
169
+ reject({
170
+ rejectionMessage: error_1 === null || error_1 === void 0 ? void 0 : error_1.message,
171
+ data: null,
172
+ });
173
+ reject(error_1);
174
+ return [3 /*break*/, 4];
175
+ case 4: return [2 /*return*/];
176
+ }
177
+ });
178
+ }); })];
179
+ });
180
+ });
181
+ };
182
+ exports.validateReceipt = validateReceipt;
@@ -0,0 +1,6 @@
1
+ import { IIAPAppleConfig, IReceiptValidationResponseBody, PurchasedItem } from '../../types';
2
+ export declare function validate(receipt: string, config: IIAPAppleConfig): Promise<IReceiptValidationResponseBody>;
3
+ export declare const isValidated: (response: IReceiptValidationResponseBody) => boolean;
4
+ export declare const isExpired: (purchasedItem: PurchasedItem) => boolean;
5
+ export declare const isCanceled: (purchasedItem: PurchasedItem) => boolean;
6
+ export declare const getPurchaseData: (purchase?: IReceiptValidationResponseBody) => PurchasedItem[];
@@ -0,0 +1,187 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __generator = (this && this.__generator) || function (thisArg, body) {
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
+ function verb(n) { return function (v) { return step([n, v]); }; }
15
+ function step(op) {
16
+ if (f) throw new TypeError("Generator is already executing.");
17
+ while (_) try {
18
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
19
+ if (y = 0, t) op = [op[0] & 2, t.value];
20
+ switch (op[0]) {
21
+ case 0: case 1: t = op; break;
22
+ case 4: _.label++; return { value: op[1], done: false };
23
+ case 5: _.label++; y = op[1]; op = [0]; continue;
24
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
25
+ default:
26
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
27
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
28
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
29
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
30
+ if (t[2]) _.ops.pop();
31
+ _.trys.pop(); continue;
32
+ }
33
+ op = body.call(thisArg, _);
34
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
35
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
36
+ }
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.getPurchaseData = exports.isCanceled = exports.isExpired = exports.isValidated = exports.validate = void 0;
40
+ var internal_1 = require("../internal");
41
+ var constants_1 = require("../../constants");
42
+ function validate(receipt, config) {
43
+ return __awaiter(this, void 0, void 0, function () {
44
+ var logger;
45
+ var _this = this;
46
+ return __generator(this, function (_a) {
47
+ logger = config.logger;
48
+ return [2 /*return*/, new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () {
49
+ var validatedData, err_1;
50
+ var _a, _b, _c;
51
+ return __generator(this, function (_d) {
52
+ switch (_d.label) {
53
+ case 0:
54
+ validatedData = null;
55
+ _d.label = 1;
56
+ case 1:
57
+ _d.trys.push([1, 6, , 7]);
58
+ if (!!config.test) return [3 /*break*/, 3];
59
+ return [4 /*yield*/, (0, internal_1.validateReceipt)({
60
+ logger: logger,
61
+ validationEndpoint: constants_1.PROD_PATH,
62
+ receipt: receipt,
63
+ password: config.applePassword,
64
+ excludeOldTransactions: Boolean(config.appleExcludeOldTransactions),
65
+ })];
66
+ case 2:
67
+ validatedData = _d.sent();
68
+ _d.label = 3;
69
+ case 3:
70
+ if (!!validatedData) return [3 /*break*/, 5];
71
+ return [4 /*yield*/, (0, internal_1.validateReceipt)({
72
+ logger: logger,
73
+ validationEndpoint: constants_1.SANDBOX_PATH,
74
+ receipt: receipt,
75
+ password: config.applePassword,
76
+ excludeOldTransactions: Boolean(config.appleExcludeOldTransactions),
77
+ })];
78
+ case 4:
79
+ validatedData = _d.sent();
80
+ _d.label = 5;
81
+ case 5:
82
+ if (!validatedData) {
83
+ reject({
84
+ rejectionMessage: 'Unable to validate receipt using appstore endpoints.',
85
+ data: null,
86
+ });
87
+ return [2 /*return*/];
88
+ }
89
+ return [3 /*break*/, 7];
90
+ case 6:
91
+ err_1 = _d.sent();
92
+ reject(err_1);
93
+ return [2 /*return*/];
94
+ case 7:
95
+ if (validatedData.status === constants_1.RECEIPT_STATUS_ENUM.SUCCESS) {
96
+ if (((_a = validatedData.receipt) === null || _a === void 0 ? void 0 : _a.in_app) && ((_c = (_b = validatedData.receipt) === null || _b === void 0 ? void 0 : _b.in_app) === null || _c === void 0 ? void 0 : _c.length) === 0) {
97
+ /*
98
+ Detected valid receipt,
99
+ but the receipt bought nothing
100
+ probably hacked: https://forums.developer.apple.com/thread/8954
101
+ https://developer.apple.com/library/mac/technotes/tn2413/_index.html#//apple_ref/doc/uid/DTS40016228-CH1-RECEIPT-HOW_DO_I_USE_THE_CANCELLATION_DATE_FIELD_
102
+ */
103
+ reject({
104
+ rejectionMessage: 'Detected valid receipt, however purchase list is empty',
105
+ data: validatedData,
106
+ });
107
+ }
108
+ // validated successfully
109
+ resolve(validatedData);
110
+ return [2 /*return*/];
111
+ }
112
+ // failed to validate reject with apple message
113
+ reject({
114
+ rejectionMessage: constants_1.STATUS_TO_MESSAGE_MAP[validatedData.status],
115
+ data: validatedData,
116
+ });
117
+ return [2 /*return*/];
118
+ }
119
+ });
120
+ }); })];
121
+ });
122
+ });
123
+ }
124
+ exports.validate = validate;
125
+ var isValidated = function (response) {
126
+ return response && response.status === constants_1.RECEIPT_STATUS_ENUM.SUCCESS;
127
+ };
128
+ exports.isValidated = isValidated;
129
+ var isExpired = function (purchasedItem) {
130
+ if (!purchasedItem || !purchasedItem.transactionId) {
131
+ throw new Error('Detected invalid purchased item! Make sure object is defined and it has transaction id.');
132
+ }
133
+ // it has been cancelled
134
+ if (purchasedItem.cancellationDateMS) {
135
+ return true;
136
+ }
137
+ // there is no expiration date with this item
138
+ if (!purchasedItem.expirationDateMS) {
139
+ return false;
140
+ }
141
+ // has expired
142
+ if (Date.now() - purchasedItem.expirationDateMS >= 0) {
143
+ return true;
144
+ }
145
+ // has not expired yet
146
+ return false;
147
+ };
148
+ exports.isExpired = isExpired;
149
+ var isCanceled = function (purchasedItem) {
150
+ if (!purchasedItem || !purchasedItem.transactionId) {
151
+ throw new Error('Detected invalid purchased item! Make sure object is defined and it has transaction id.');
152
+ }
153
+ return Boolean(purchasedItem.cancellationDateMS);
154
+ };
155
+ exports.isCanceled = isCanceled;
156
+ var getPurchaseData = function (purchase) {
157
+ if (!purchase || !purchase.receipt) {
158
+ return [];
159
+ }
160
+ var data = [];
161
+ var purchases = purchase.receipt.in_app || [];
162
+ var lri = purchase.latest_receipt_info || purchase.receipt.latest_receipt_info;
163
+ if (Array.isArray(lri)) {
164
+ purchases = purchases.concat(lri);
165
+ }
166
+ /*
167
+ we sort purchases by purchase_date_ms to make it easier
168
+ to weed out duplicates (items with the same original_transaction_id)
169
+ purchase_date_ms DESC
170
+ */
171
+ purchases.sort(function (a, b) {
172
+ return parseInt(b.purchase_date_ms, 10) - parseInt(a.purchase_date_ms, 10);
173
+ });
174
+ var transactionIds = {};
175
+ for (var i = 0; i < purchases.length; i++) {
176
+ var item = purchases[i];
177
+ var tid = item.original_transaction_id;
178
+ // avoid duplicate
179
+ if (transactionIds[tid]) {
180
+ continue;
181
+ }
182
+ data.push((0, internal_1.getPurchaseItem)(item, purchase));
183
+ transactionIds[tid] = true;
184
+ }
185
+ return data;
186
+ };
187
+ exports.getPurchaseData = getPurchaseData;
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "iap-apple",
3
- "version": "1.3.3",
3
+ "version": "1.3.5",
4
4
  "description": "Integration with Apples InAppPurchases in Typescript, available for NodeJS environments.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
7
  "scripts": {
8
- "prebuild": "yarn code-quality:check",
9
8
  "build": "rm -rf dist && tsc --project tsconfig.build.json && cp package.json dist/package.json",
10
9
  "format": "prettier --write \"src/**/*.ts\"",
11
10
  "test": "nyc --reporter=json-summary mocha --bail --slow 1 --timeout 60000 --require ts-node/register/transpile-only src/**/*.spec.ts",
@@ -74,11 +73,6 @@
74
73
  "ts-node": "10.9.1",
75
74
  "typescript": "4.8.4"
76
75
  },
77
- "files": [
78
- "src/**/*",
79
- "dist/**/*",
80
- "README.md"
81
- ],
82
76
  "dependencies": {
83
77
  "superagent": "8.0.6"
84
78
  },
@@ -150,7 +144,12 @@
150
144
  }
151
145
  }
152
146
  ],
153
- "@semantic-release/npm",
147
+ [
148
+ "@semantic-release/npm",
149
+ {
150
+ "pkgRoot": "./dist"
151
+ }
152
+ ],
154
153
  "@semantic-release/release-notes-generator",
155
154
  "@semantic-release/changelog",
156
155
  [
File without changes
package/types/index.js ADDED
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./internal"), exports);
18
+ __exportStar(require("./shared"), exports);
@@ -0,0 +1,41 @@
1
+ import { RECEIPT_STATUS_ENUM } from '../../constants';
2
+ interface IReceipt {
3
+ bundle_id: string;
4
+ application_version: string;
5
+ in_app: IReceiptInAppItem[];
6
+ latest_receipt_info: IReceiptInAppItem[];
7
+ original_application_version: string;
8
+ receipt_creation_date_ms: string;
9
+ expiration_date_ms: string;
10
+ original_purchase_date: string;
11
+ app_item_id: string;
12
+ version_external_identifier: string;
13
+ expires_date_ms?: string;
14
+ }
15
+ export interface IReceiptInAppItem {
16
+ quantity: string;
17
+ product_id: string;
18
+ transaction_id: string;
19
+ original_transaction_id: string;
20
+ purchase_date: string;
21
+ purchase_date_ms: string;
22
+ original_purchase_date: string;
23
+ original_purchase_date_ms: string;
24
+ expires_date?: string;
25
+ expires_date_ms?: string;
26
+ expiration_intent?: '1' | '2' | '3' | '4' | '5';
27
+ is_trial_period: string;
28
+ cancellation_date?: string;
29
+ cancellation_date_ms?: string;
30
+ cancellation_reason?: '0' | '1';
31
+ app_item_id: string;
32
+ }
33
+ export interface IReceiptValidationResponseBody {
34
+ status: RECEIPT_STATUS_ENUM;
35
+ environment: 'Sandbox' | 'Production';
36
+ receipt: IReceipt;
37
+ latest_receipt: string;
38
+ latest_receipt_info: IReceiptInAppItem[];
39
+ 'is-retryable': boolean;
40
+ }
41
+ export {};
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,29 @@
1
+ import { IReceiptValidationResponseBody } from '../../types/internal';
2
+ export interface ILogger {
3
+ log: (message: string) => void;
4
+ warn: (message: string) => void;
5
+ error: (message: string) => void;
6
+ }
7
+ export interface IIAPAppleConfig {
8
+ appleExcludeOldTransactions?: boolean | undefined;
9
+ applePassword?: string | undefined;
10
+ test?: boolean | undefined;
11
+ logger?: ILogger | null;
12
+ }
13
+ export interface PurchasedItem {
14
+ bundleId: string;
15
+ appItemId: string;
16
+ originalTransactionId?: string;
17
+ transactionId: string;
18
+ productId: string;
19
+ originalPurchaseDate?: number;
20
+ expirationDateMS?: number;
21
+ purchaseDateMS: number;
22
+ isTrialPeriod: boolean;
23
+ cancellationDateMS?: number;
24
+ quantity: number;
25
+ }
26
+ export interface IAPAppleError {
27
+ rejectionMessage: string;
28
+ data?: IReceiptValidationResponseBody | null;
29
+ }