From 3ee3734fd5d4bee92b11c93338e1e345ff75d817 Mon Sep 17 00:00:00 2001 From: Antonio Marino Date: Fri, 4 Jan 2019 15:47:49 +0000 Subject: [PATCH 01/21] Added defer subscription for google play --- README.md | 15 +++++++++++++ index.js | 32 +++++++++++++++++++++++++++ lib/google/index.js | 53 +++++++++++++++++++++++++++++++++++++++++++++ lib/google/urls.js | 14 ++++++++++-- 4 files changed, 112 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6660a5f..9e0fd6d 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,21 @@ iap.cancelSubscription("google", payment, function (error, response) { }); ``` +### Subscription deferral ( Google Play only ) + +Google exposes [an API for deferral](https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/defer) of recurring suscriptions. This might be +be used to extend a user's subscription purchase until a specified future expiration time ( useful to grant your users some free days or months ). + +```javascript +var deferralInfo = { + expectedExpiryTimeMillis: 1546616722237, + desiredExpiryTimeMillis: 1547716722237, +}; +iap.deferSubscription("google", payment, deferralInfo, function (error, response) { + /* your code */ +}); +``` + ## Supported platforms ### Amazon diff --git a/index.js b/index.js index fa8a17b..c495bef 100644 --- a/index.js +++ b/index.js @@ -67,3 +67,35 @@ exports.cancelSubscription = function (platform, payment, cb) { cb(null, result); }); }; + + +exports.deferSubscription = function (platform, payment, deferralInfo, cb) { + function syncError(error) { + process.nextTick(function () { + cb(error); + }); + } + + if (!payment) { + return syncError(new Error('No payment given')); + } + + var engine = platforms[platform]; + + if (!engine) { + return syncError(new Error('Platform ' + platform + ' not recognized')); + } + + if (!engine.deferSubscription) { + return syncError(new Error('Platform ' + platform + + ' does not have deferSubscription method')); + } + + engine.deferSubscription(payment, deferralInfo, function (error, result) { + if (error) { + return cb(error); + } + + cb(null, result); + }); +}; diff --git a/lib/google/index.js b/lib/google/index.js index 07b621a..d49c60a 100644 --- a/lib/google/index.js +++ b/lib/google/index.js @@ -41,6 +41,14 @@ function validatePaymentAndParseKeyObject(payment) { return keyObject; } +function validateDeferralInfo(deferralInfo) { + assert.equal(typeof deferralInfo, 'object', 'deferralInfo must be an object'); + assert.equal(typeof deferralInfo.expectedExpiryTimeMillis, 'number', 'expectedExpiryTimeMillis must be a number'); + assert.equal(typeof deferralInfo.desiredExpiryTimeMillis, 'number', 'desiredExpiryTimeMillis must be a number'); + assert(deferralInfo.desiredExpiryTimeMillis > deferralInfo.expectedExpiryTimeMillis, 'desiredExpiryTimeMillis must be greater than expectedExpiryTimeMillis'); +} + + exports.verifyPayment = function (payment, cb) { var keyObject; @@ -133,3 +141,48 @@ exports.cancelSubscription = function (payment, cb) { }); }); }; + + +exports.cancelSubscription = function (payment, deferralInfo, cb) { + var keyObject; + + try { + keyObject = validatePaymentAndParseKeyObject(payment); + validateDeferralInfo(deferralInfo); + } catch (error) { + return process.nextTick(function () { + cb(error); + }); + } + + jwt.getToken(keyObject.client_email, keyObject.private_key, apiUrls.publisherScope, function (error, token) { + if (error) { + return cb(error); + } + + var requestUrl = apiUrls.purchasesSubscriptionsDefer( + payment.packageName, + payment.productId, + payment.receipt, + token + ); + + https.post(requestUrl, null, function (error, res, resultString) { + if (error) { + return cb(error); + } + + if (res.statusCode !== 200) { + return cb(new Error('Received ' + res.statusCode + ' status code with body: ' + resultString)); + } + + try { + var resultObject = JSON.parse(resultString); + } catch (e) { + return cb(e); + } + + return cb(null, resultObject); + }); + }); +}; diff --git a/lib/google/urls.js b/lib/google/urls.js index 4534949..13943ed 100644 --- a/lib/google/urls.js +++ b/lib/google/urls.js @@ -38,8 +38,6 @@ exports.purchasesSubscriptionsGet = function (packageName, productId, receipt, a ); }; - -// Android Subscriptions URLs & generators exports.purchasesSubscriptionsCancel = function (packageName, productId, receipt, accessToken) { var urlFormat = 'https://www.googleapis.com/androidpublisher/v2/applications/%s/purchases/subscriptions/%s/tokens/%s:cancel?access_token=%s'; @@ -51,3 +49,15 @@ exports.purchasesSubscriptionsCancel = function (packageName, productId, receipt encodeURIComponent(accessToken) // API access token ); }; + +exports.purchasesSubscriptionsDefer = function (packageName, productId, receipt, accessToken) { + var urlFormat = 'https://www.googleapis.com/androidpublisher/v2/applications/%s/purchases/subscriptions/%s/tokens/%s:defer?access_token=%s'; + + return util.format( + urlFormat, + encodeURIComponent(packageName), // application package name + encodeURIComponent(productId), // productId + encodeURIComponent(receipt), // purchase token + encodeURIComponent(accessToken) // API access token + ); +}; From bfdbc8fae8b0a88e2d6a289b276c585feba96503 Mon Sep 17 00:00:00 2001 From: Antonio Marino Date: Fri, 4 Jan 2019 17:36:22 +0000 Subject: [PATCH 02/21] fix --- lib/google/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/google/index.js b/lib/google/index.js index d49c60a..81dbebb 100644 --- a/lib/google/index.js +++ b/lib/google/index.js @@ -143,7 +143,7 @@ exports.cancelSubscription = function (payment, cb) { }; -exports.cancelSubscription = function (payment, deferralInfo, cb) { +exports.deferSubscription = function (payment, deferralInfo, cb) { var keyObject; try { From e1f1b6c4e86d402de1a2010373d02d0ffd076131 Mon Sep 17 00:00:00 2001 From: Antonio Marino Date: Sun, 6 Jan 2019 19:02:11 +0000 Subject: [PATCH 03/21] passing deferralInfo --- lib/google/index.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/google/index.js b/lib/google/index.js index 81dbebb..54d6ae1 100644 --- a/lib/google/index.js +++ b/lib/google/index.js @@ -167,7 +167,12 @@ exports.deferSubscription = function (payment, deferralInfo, cb) { token ); - https.post(requestUrl, null, function (error, res, resultString) { + var options = { + json: { + deferralInfo, + } + } + https.post(requestUrl, options, function (error, res, resultString) { if (error) { return cb(error); } From 7e7043e208fbebf8f23a3142c0fac70cdaaa710f Mon Sep 17 00:00:00 2001 From: Antonio Marino Date: Sun, 6 Jan 2019 19:32:27 +0000 Subject: [PATCH 04/21] fix lint --- lib/google/index.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/google/index.js b/lib/google/index.js index 54d6ae1..f10ed37 100644 --- a/lib/google/index.js +++ b/lib/google/index.js @@ -169,9 +169,9 @@ exports.deferSubscription = function (payment, deferralInfo, cb) { var options = { json: { - deferralInfo, + deferralInfo } - } + }; https.post(requestUrl, options, function (error, res, resultString) { if (error) { return cb(error); @@ -181,8 +181,9 @@ exports.deferSubscription = function (payment, deferralInfo, cb) { return cb(new Error('Received ' + res.statusCode + ' status code with body: ' + resultString)); } + var resultObject; try { - var resultObject = JSON.parse(resultString); + resultObject = JSON.parse(resultString); } catch (e) { return cb(e); } From 63b7f6404a816c11190f943b30a82311ef8e9a0a Mon Sep 17 00:00:00 2001 From: Antonio Marino Date: Mon, 3 Jun 2019 12:53:52 +0100 Subject: [PATCH 05/21] fixed indentation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9e0fd6d..31dc075 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ be used to extend a user's subscription purchase until a specified future expira ```javascript var deferralInfo = { expectedExpiryTimeMillis: 1546616722237, - desiredExpiryTimeMillis: 1547716722237, + desiredExpiryTimeMillis: 1547716722237, }; iap.deferSubscription("google", payment, deferralInfo, function (error, response) { /* your code */ From 18f6fd8e483fb70d72c9e1438eee9364c84a0209 Mon Sep 17 00:00:00 2001 From: VK432 Date: Fri, 15 Nov 2019 00:08:18 +0000 Subject: [PATCH 06/21] google deferral (#1) --- README.md | 3 +-- index.js | 12 ++++++++---- lib/google/index.js | 19 ++++++++++--------- lib/google/urls.js | 3 ++- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 31dc075..07e51c9 100644 --- a/README.md +++ b/README.md @@ -59,8 +59,7 @@ iap.cancelSubscription("google", payment, function (error, response) { ### Subscription deferral ( Google Play only ) -Google exposes [an API for deferral](https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/defer) of recurring suscriptions. This might be -be used to extend a user's subscription purchase until a specified future expiration time ( useful to grant your users some free days or months ). +Google exposes [an API for deferral](https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/defer) of recurring suscriptions. This might be used to extend a user's subscription purchase until a specified future expiration time ( useful to grant your users some free days or months ). ```javascript var deferralInfo = { diff --git a/index.js b/index.js index 12bc574..af022ad 100644 --- a/index.js +++ b/index.js @@ -80,15 +80,19 @@ exports.deferSubscription = function (platform, payment, deferralInfo, cb) { return syncError(new Error('No payment given')); } - var engine = platforms[platform]; + if (!deferralInfo) { + return syncError(new Error('No deferralInfo given')); + } + + const engine = platforms[platform]; if (!engine) { - return syncError(new Error('Platform ' + platform + ' not recognized')); + return syncError(new Error(`Platform ${platform} not recognized`)); } if (!engine.deferSubscription) { - return syncError(new Error('Platform ' + platform + - ' does not have deferSubscription method')); + return syncError(new Error(`Platform ${platform + } does not have deferSubscription method`)); } engine.deferSubscription(payment, deferralInfo, function (error, result) { diff --git a/lib/google/index.js b/lib/google/index.js index cc33adc..9bc27cd 100644 --- a/lib/google/index.js +++ b/lib/google/index.js @@ -45,7 +45,10 @@ function validateDeferralInfo(deferralInfo) { assert.equal(typeof deferralInfo, 'object', 'deferralInfo must be an object'); assert.equal(typeof deferralInfo.expectedExpiryTimeMillis, 'number', 'expectedExpiryTimeMillis must be a number'); assert.equal(typeof deferralInfo.desiredExpiryTimeMillis, 'number', 'desiredExpiryTimeMillis must be a number'); + assert(deferralInfo.desiredExpiryTimeMillis > deferralInfo.expectedExpiryTimeMillis, 'desiredExpiryTimeMillis must be greater than expectedExpiryTimeMillis'); + + return deferralInfo; } @@ -144,11 +147,14 @@ exports.cancelSubscription = function (payment, cb) { exports.deferSubscription = function (payment, deferralInfo, cb) { - var keyObject; + let keyObject; + let options; try { keyObject = validatePaymentAndParseKeyObject(payment); - validateDeferralInfo(deferralInfo); + options.json = { + deferralInfo: validateDeferralInfo(deferralInfo) + }; } catch (error) { return process.nextTick(function () { cb(error); @@ -160,25 +166,20 @@ exports.deferSubscription = function (payment, deferralInfo, cb) { return cb(error); } - var requestUrl = apiUrls.purchasesSubscriptionsDefer( + const requestUrl = apiUrls.purchasesSubscriptionsDefer( payment.packageName, payment.productId, payment.receipt, token ); - var options = { - json: { - deferralInfo - } - }; https.post(requestUrl, options, function (error, res, resultString) { if (error) { return cb(error); } if (res.statusCode !== 200) { - return cb(new Error('Received ' + res.statusCode + ' status code with body: ' + resultString)); + return cb(new Error(`Received ${res.statusCode} status code with body: ${resultString}`)); } var resultObject; diff --git a/lib/google/urls.js b/lib/google/urls.js index 633be8e..9ca002e 100644 --- a/lib/google/urls.js +++ b/lib/google/urls.js @@ -50,8 +50,9 @@ exports.purchasesSubscriptionsCancel = function (packageName, productId, receipt ); }; +// Android Subscriptions URLs & generators exports.purchasesSubscriptionsDefer = function (packageName, productId, receipt, accessToken) { - var urlFormat = 'https://www.googleapis.com/androidpublisher/v2/applications/%s/purchases/subscriptions/%s/tokens/%s:defer?access_token=%s'; + const urlFormat = 'https://www.googleapis.com/androidpublisher/v3/applications/%s/purchases/subscriptions/%s/tokens/%s:defer?access_token=%s'; return util.format( urlFormat, From 408a0dc4211c6e4fac73c14138ad8b0b21a214d3 Mon Sep 17 00:00:00 2001 From: Antonio Marino Date: Mon, 18 Nov 2019 20:01:22 +0000 Subject: [PATCH 07/21] Bug fix --- lib/google/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/google/index.js b/lib/google/index.js index 9bc27cd..47e1f4c 100644 --- a/lib/google/index.js +++ b/lib/google/index.js @@ -148,7 +148,7 @@ exports.cancelSubscription = function (payment, cb) { exports.deferSubscription = function (payment, deferralInfo, cb) { let keyObject; - let options; + let options = {}; try { keyObject = validatePaymentAndParseKeyObject(payment); From cf9265061a8692ee78e66066c35f83f1b0aa8317 Mon Sep 17 00:00:00 2001 From: Antonio Marino Date: Tue, 19 Nov 2019 01:28:04 +0000 Subject: [PATCH 08/21] lint fix --- lib/google/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/google/index.js b/lib/google/index.js index 47e1f4c..b669d2d 100644 --- a/lib/google/index.js +++ b/lib/google/index.js @@ -148,7 +148,7 @@ exports.cancelSubscription = function (payment, cb) { exports.deferSubscription = function (payment, deferralInfo, cb) { let keyObject; - let options = {}; + const options = {}; try { keyObject = validatePaymentAndParseKeyObject(payment); From ed711f9c693106de6283c53dba2ce75a5ac49baa Mon Sep 17 00:00:00 2001 From: Andrew Shini <13059204+superandrew213@users.noreply.github.com> Date: Fri, 22 Nov 2019 19:53:47 +1000 Subject: [PATCH 09/21] [Apple] Check for cancellation_date_ms first (#50) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [Apple] Check for cancellation_date_ms first If cancellation date is available it means that Apple Customer Support refunded subscription payment. From Apple: To check whether a purchase has been canceled by Apple Customer Support, look for the Cancellation Date field in the receipt. If the field contains a date, regardless of the subscription’s expiration date, the purchase has been canceled. With respect to providing content or service, treat a canceled transaction the same as if no purchase had ever been made. --- lib/apple/index.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/apple/index.js b/lib/apple/index.js index 89e2043..aac972a 100644 --- a/lib/apple/index.js +++ b/lib/apple/index.js @@ -78,7 +78,10 @@ function parseResult(result) { productId = lastReceipt.product_id; transactionId = lastReceipt.transaction_id; purchaseDate = parseTime(lastReceipt.purchase_date_ms); - expirationDate = parseTime(lastReceipt.expires_date_ms || lastReceipt.expires_date); + expirationDate = parseTime( + lastReceipt.expires_date_ms || + lastReceipt.expires_date + ); } else if (result.latest_receipt_info && result.latest_receipt_info.transaction_id) { latestReceiptInfo = [result.latest_receipt_info]; @@ -86,11 +89,22 @@ function parseResult(result) { transactionId = result.latest_receipt_info.transaction_id; purchaseDate = parseTime(result.latest_receipt_info.purchase_date_ms); expirationDate = parseTime( - result.latest_receipt_info.expires_date_ms || result.latest_receipt_info.expires_date + result.latest_receipt_info.expires_date_ms || + result.latest_receipt_info.expires_date ); } } + // If cancellation date is available it means that Apple Customer Support refunded subscription payment. + // From Apple: + // To check whether a purchase has been canceled by Apple Customer Support, look for the + // Cancellation Date field in the receipt. If the field contains a date, regardless of the + // subscription’s expiration date, the purchase has been canceled. With respect to providing + // content or service, treat a canceled transaction the same as if no purchase had ever been made. + if (latestExpiredReceiptInfo && latestExpiredReceiptInfo.cancellation_date_ms) { + expirationDate = parseTime(latestExpiredReceiptInfo.cancellation_date_ms); + } + return { receipt: result.receipt, latestReceiptInfo, From cbd797316553446d3457a6186788d5324410579d Mon Sep 17 00:00:00 2001 From: Justin Page Date: Mon, 16 Dec 2019 10:44:29 -0800 Subject: [PATCH 10/21] Update available response status codes from apple Referencing the following documentation: https://developer.apple.com/documentation/appstorereceipts/status We can see that 21009 and 21010 are available codes we should handle. --- lib/apple/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/apple/index.js b/lib/apple/index.js index aac972a..f2a19a5 100644 --- a/lib/apple/index.js +++ b/lib/apple/index.js @@ -16,7 +16,9 @@ const responses = { 21005: 'The receipt server is not currently available.', 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.', 21007: 'This receipt is from the test environment, but it was sent to the production service for verification. Send it to the test environment service instead.', - 21008: 'This receipt is from the production receipt, but it was sent to the test environment service for verification. Send it to the production environment service instead.' + 21008: 'This receipt is from the production receipt, but it was sent to the test environment service for verification. Send it to the production environment service instead.', + 21009: 'Internal data access error. Try again later.', + 21010: 'The user account cannot be found or has been deleted.' }; function getReceiptFieldValue(receipt, field) { From ff9b8efa248bcbfec039a0369da3d7a393b93d93 Mon Sep 17 00:00:00 2001 From: Ron Korving Date: Tue, 24 Dec 2019 17:29:29 +0900 Subject: [PATCH 11/21] Bump ESLint --- package-lock.json | 281 ++++++++++++++++++++++++++-------------------- package.json | 2 +- 2 files changed, 163 insertions(+), 120 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8ff8717..9fe625f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,15 +31,15 @@ "dev": true }, "acorn": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.2.1.tgz", - "integrity": "sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz", + "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==", "dev": true }, "acorn-jsx": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz", - "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", + "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==", "dev": true }, "ajv": { @@ -55,15 +55,26 @@ } }, "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.0.tgz", + "integrity": "sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } }, "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", "dev": true }, "ansi-styles": { @@ -78,7 +89,7 @@ "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { "sprintf-js": "~1.0.2" @@ -162,12 +173,12 @@ "dev": true }, "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, "requires": { - "restore-cursor": "^2.0.0" + "restore-cursor": "^3.1.0" } }, "cli-width": { @@ -265,9 +276,9 @@ } }, "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "end-of-stream": { @@ -295,9 +306,9 @@ "dev": true }, "eslint": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.1.0.tgz", - "integrity": "sha512-QhrbdRD7ofuV09IuE2ySWBz0FyXCq0rriLTZXZqaWSI79CVtHVRdkFuFTViiqzZhkCgfOh9USpriuGN2gIpZDQ==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -307,19 +318,19 @@ "debug": "^4.0.1", "doctrine": "^3.0.0", "eslint-scope": "^5.0.0", - "eslint-utils": "^1.3.1", - "eslint-visitor-keys": "^1.0.0", - "espree": "^6.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", "esquery": "^1.0.1", "esutils": "^2.0.2", "file-entry-cache": "^5.0.1", "functional-red-black-tree": "^1.0.1", "glob-parent": "^5.0.0", - "globals": "^11.7.0", + "globals": "^12.1.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", - "inquirer": "^6.4.1", + "inquirer": "^7.0.0", "is-glob": "^4.0.0", "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.1", @@ -328,7 +339,7 @@ "minimatch": "^3.0.4", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", - "optionator": "^0.8.2", + "optionator": "^0.8.3", "progress": "^2.0.0", "regexpp": "^2.0.1", "semver": "^6.1.2", @@ -358,29 +369,29 @@ } }, "eslint-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.0.tgz", - "integrity": "sha512-7ehnzPaP5IIEh1r1tkjuIrxqhNkzUJa9z3R92tLJdZIVdWaczEhr3EbhGtsMrVxi1KeR8qA7Off6SWc5WNQqyQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.0.0" + "eslint-visitor-keys": "^1.1.0" } }, "eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", "dev": true }, "espree": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.0.0.tgz", - "integrity": "sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.1.2.tgz", + "integrity": "sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==", "dev": true, "requires": { - "acorn": "^6.0.7", - "acorn-jsx": "^5.0.0", - "eslint-visitor-keys": "^1.0.0" + "acorn": "^7.1.0", + "acorn-jsx": "^5.1.0", + "eslint-visitor-keys": "^1.1.0" } }, "esprima": { @@ -408,9 +419,9 @@ } }, "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "esutils": { @@ -452,9 +463,9 @@ "dev": true }, "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, "fast-levenshtein": { @@ -464,9 +475,9 @@ "dev": true }, "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.1.0.tgz", + "integrity": "sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==", "dev": true, "requires": { "escape-string-regexp": "^1.0.5" @@ -536,9 +547,9 @@ } }, "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -550,19 +561,30 @@ } }, "glob-parent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz", - "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", "dev": true, "requires": { "is-glob": "^4.0.1" } }, "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.3.0.tgz", + "integrity": "sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } + } }, "has-flag": { "version": "3.0.0", @@ -611,9 +633,9 @@ "dev": true }, "import-fresh": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.1.0.tgz", - "integrity": "sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", + "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -643,22 +665,22 @@ "dev": true }, "inquirer": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.0.tgz", - "integrity": "sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.0.1.tgz", + "integrity": "sha512-V1FFQ3TIO15det8PijPLFR9M9baSlnRs9nL7zWu1MNVA2T9YVl9ZbrHJhYs7e9X8jeMZ3lr2JH/rdHFgNCBdYw==", "dev": true, "requires": { - "ansi-escapes": "^3.2.0", + "ansi-escapes": "^4.2.1", "chalk": "^2.4.2", - "cli-cursor": "^2.1.0", + "cli-cursor": "^3.1.0", "cli-width": "^2.0.0", "external-editor": "^3.0.3", - "figures": "^2.0.0", - "lodash": "^4.17.12", - "mute-stream": "0.0.7", + "figures": "^3.0.0", + "lodash": "^4.17.15", + "mute-stream": "0.0.8", "run-async": "^2.2.0", - "rxjs": "^6.4.0", - "string-width": "^2.1.0", + "rxjs": "^6.5.3", + "string-width": "^4.1.0", "strip-ansi": "^5.1.0", "through": "^2.3.6" } @@ -691,9 +713,9 @@ "dev": true }, "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, "is-glob": { @@ -794,9 +816,9 @@ "dev": true }, "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, "minimatch": { @@ -829,9 +851,9 @@ "dev": true }, "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, "natural-compare": { @@ -877,12 +899,12 @@ } }, "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", "dev": true, "requires": { - "mimic-fn": "^1.0.0" + "mimic-fn": "^2.1.0" } }, "opencollective-postinstall": { @@ -892,17 +914,17 @@ "dev": true }, "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", "dev": true, "requires": { "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", + "fast-levenshtein": "~2.0.6", "levn": "~0.3.0", "prelude-ls": "~1.1.2", "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "word-wrap": "~1.2.3" } }, "os-tmpdir": { @@ -1078,12 +1100,12 @@ "dev": true }, "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, "requires": { - "onetime": "^2.0.0", + "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, @@ -1112,9 +1134,9 @@ "dev": true }, "rxjs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.2.tgz", - "integrity": "sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", "dev": true, "requires": { "tslib": "^1.9.0" @@ -1174,6 +1196,14 @@ "ansi-styles": "^3.2.0", "astral-regex": "^1.0.0", "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } } }, "spdx-correct": { @@ -1215,22 +1245,23 @@ "dev": true }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", "dev": true, "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" }, "dependencies": { "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "dev": true, "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^5.0.0" } } } @@ -1274,9 +1305,9 @@ } }, "table": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.5.tgz", - "integrity": "sha512-oGa2Hl7CQjfoaogtrOHEJroOcYILTx7BZWLGsJIlzoWmB2zmguhNfPJZsWPKYek/MgCxfco54gEi31d1uN2hFA==", + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", "dev": true, "requires": { "ajv": "^6.10.2", @@ -1285,6 +1316,18 @@ "string-width": "^3.0.0" }, "dependencies": { + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -1350,9 +1393,9 @@ } }, "v8-compile-cache": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz", - "integrity": "sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", "dev": true }, "validate-npm-package-license": { @@ -1374,10 +1417,10 @@ "isexe": "^2.0.0" } }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, "wrappy": { diff --git a/package.json b/package.json index d97eff6..46fb4ef 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "minimist": "0.0.8" }, "devDependencies": { - "eslint": "6.1.0", + "eslint": "6.8.0", "husky": "3.0.2" }, "husky": { From 16f7e72552cad6bad277f88807d9d4e04fa3907f Mon Sep 17 00:00:00 2001 From: Ron Korving Date: Tue, 24 Dec 2019 18:10:14 +0900 Subject: [PATCH 12/21] Release 1.1.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9fe625f..8caade0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "iap", - "version": "1.1.0", + "version": "1.1.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 46fb4ef..c475989 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "iap", - "version": "1.1.0", + "version": "1.1.1", "description": "In-app purchase validation for Apple, Google, Amazon, Roku", "main": "index.js", "scripts": { From 4ac0e22a54008a8396599190ea75a80b038ae407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Louren=C3=A7o?= Date: Thu, 23 Jan 2020 08:25:42 +0000 Subject: [PATCH 13/21] Created verifyPayment alternative function to return Promise (#69) verifyPayment and cancelSubscription now return promises if no callback is passed --- README.md | 30 +++++++++++++++++++++++++++++- index.js | 24 ++++++++++++++++++++---- 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6660a5f..7d592ff 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ var payment = { ### Purchase verification ( all platforms ) -A single method is exposed to verify purchase receipts: +A method is exposed to verify purchase receipts: ```javascript iap.verifyPayment(platform, payment, function (error, response) { @@ -41,6 +41,20 @@ iap.verifyPayment(platform, payment, function (error, response) { }); ``` +Or, if you prefer a promise-based alternative: + +```javascript +iap.verifyPayment(platform, payment) +.then( + response => { + /* your code */ + }, + error => { + /* your code */ + } +) +``` + The receipt you pass must conform to the requirements of the backend you are verifying with. Read the next chapter for more information on the format. @@ -57,6 +71,20 @@ iap.cancelSubscription("google", payment, function (error, response) { }); ``` +Or, if you prefer a promise-based alternative: + +```javascript +iap.cancelSubscription(platform, payment) +.then( + response => { + /* your code */ + }, + error => { + /* your code */ + } +) +``` + ## Supported platforms ### Amazon diff --git a/index.js b/index.js index e7220b4..7c51396 100644 --- a/index.js +++ b/index.js @@ -7,8 +7,17 @@ const platforms = { roku: require('./lib/roku') }; +const promisify = (fn) => { + return (...args) => { + return new Promise((resolve, reject) => { + fn(...args, (err, res) => { + return (err ? reject(err) : resolve(res)); + }); + }); + }; +}; -exports.verifyPayment = function (platform, payment, cb) { +function verifyPayment(platform, payment, cb) { function syncError(error) { process.nextTick(function () { cb(error); @@ -34,10 +43,9 @@ exports.verifyPayment = function (platform, payment, cb) { cb(null, result); }); -}; - +} -exports.cancelSubscription = function (platform, payment, cb) { +function cancelSubscription(platform, payment, cb) { function syncError(error) { process.nextTick(function () { cb(error); @@ -66,4 +74,12 @@ exports.cancelSubscription = function (platform, payment, cb) { cb(null, result); }); +} + +exports.verifyPayment = (platform, payment, cb) => { + return (cb ? verifyPayment(platform, payment, cb) : promisify(verifyPayment)(platform, payment)); +}; + +exports.cancelSubscription = (platform, payment, cb) => { + return (cb ? cancelSubscription(platform, payment, cb) : promisify(cancelSubscription)(platform, payment)); }; From 3bb5c964d894d42a1221b34634cec89a4b909c82 Mon Sep 17 00:00:00 2001 From: Antonio Marino Date: Fri, 4 Jan 2019 15:47:49 +0000 Subject: [PATCH 14/21] Added defer subscription for google play --- README.md | 15 +++++++++++++ index.js | 32 +++++++++++++++++++++++++++ lib/google/index.js | 53 +++++++++++++++++++++++++++++++++++++++++++++ lib/google/urls.js | 14 ++++++++++-- 4 files changed, 112 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7d592ff..3c95842 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,21 @@ iap.cancelSubscription(platform, payment) ) ``` +### Subscription deferral ( Google Play only ) + +Google exposes [an API for deferral](https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/defer) of recurring suscriptions. This might be +be used to extend a user's subscription purchase until a specified future expiration time ( useful to grant your users some free days or months ). + +```javascript +var deferralInfo = { + expectedExpiryTimeMillis: 1546616722237, + desiredExpiryTimeMillis: 1547716722237, +}; +iap.deferSubscription("google", payment, deferralInfo, function (error, response) { + /* your code */ +}); +``` + ## Supported platforms ### Amazon diff --git a/index.js b/index.js index 7c51396..92d6479 100644 --- a/index.js +++ b/index.js @@ -83,3 +83,35 @@ exports.verifyPayment = (platform, payment, cb) => { exports.cancelSubscription = (platform, payment, cb) => { return (cb ? cancelSubscription(platform, payment, cb) : promisify(cancelSubscription)(platform, payment)); }; + + +exports.deferSubscription = function (platform, payment, deferralInfo, cb) { + function syncError(error) { + process.nextTick(function () { + cb(error); + }); + } + + if (!payment) { + return syncError(new Error('No payment given')); + } + + var engine = platforms[platform]; + + if (!engine) { + return syncError(new Error('Platform ' + platform + ' not recognized')); + } + + if (!engine.deferSubscription) { + return syncError(new Error('Platform ' + platform + + ' does not have deferSubscription method')); + } + + engine.deferSubscription(payment, deferralInfo, function (error, result) { + if (error) { + return cb(error); + } + + cb(null, result); + }); +}; diff --git a/lib/google/index.js b/lib/google/index.js index ca4ae9e..3eb0300 100644 --- a/lib/google/index.js +++ b/lib/google/index.js @@ -41,6 +41,14 @@ function validatePaymentAndParseKeyObject(payment) { return keyObject; } +function validateDeferralInfo(deferralInfo) { + assert.equal(typeof deferralInfo, 'object', 'deferralInfo must be an object'); + assert.equal(typeof deferralInfo.expectedExpiryTimeMillis, 'number', 'expectedExpiryTimeMillis must be a number'); + assert.equal(typeof deferralInfo.desiredExpiryTimeMillis, 'number', 'desiredExpiryTimeMillis must be a number'); + assert(deferralInfo.desiredExpiryTimeMillis > deferralInfo.expectedExpiryTimeMillis, 'desiredExpiryTimeMillis must be greater than expectedExpiryTimeMillis'); +} + + exports.verifyPayment = function (payment, cb) { let keyObject; @@ -133,3 +141,48 @@ exports.cancelSubscription = function (payment, cb) { }); }); }; + + +exports.cancelSubscription = function (payment, deferralInfo, cb) { + var keyObject; + + try { + keyObject = validatePaymentAndParseKeyObject(payment); + validateDeferralInfo(deferralInfo); + } catch (error) { + return process.nextTick(function () { + cb(error); + }); + } + + jwt.getToken(keyObject.client_email, keyObject.private_key, apiUrls.publisherScope, function (error, token) { + if (error) { + return cb(error); + } + + var requestUrl = apiUrls.purchasesSubscriptionsDefer( + payment.packageName, + payment.productId, + payment.receipt, + token + ); + + https.post(requestUrl, null, function (error, res, resultString) { + if (error) { + return cb(error); + } + + if (res.statusCode !== 200) { + return cb(new Error('Received ' + res.statusCode + ' status code with body: ' + resultString)); + } + + try { + var resultObject = JSON.parse(resultString); + } catch (e) { + return cb(e); + } + + return cb(null, resultObject); + }); + }); +}; diff --git a/lib/google/urls.js b/lib/google/urls.js index ed23521..633be8e 100644 --- a/lib/google/urls.js +++ b/lib/google/urls.js @@ -38,8 +38,6 @@ exports.purchasesSubscriptionsGet = function (packageName, productId, receipt, a ); }; - -// Android Subscriptions URLs & generators exports.purchasesSubscriptionsCancel = function (packageName, productId, receipt, accessToken) { const urlFormat = 'https://www.googleapis.com/androidpublisher/v3/applications/%s/purchases/subscriptions/%s/tokens/%s:cancel?access_token=%s'; @@ -51,3 +49,15 @@ exports.purchasesSubscriptionsCancel = function (packageName, productId, receipt encodeURIComponent(accessToken) // API access token ); }; + +exports.purchasesSubscriptionsDefer = function (packageName, productId, receipt, accessToken) { + var urlFormat = 'https://www.googleapis.com/androidpublisher/v2/applications/%s/purchases/subscriptions/%s/tokens/%s:defer?access_token=%s'; + + return util.format( + urlFormat, + encodeURIComponent(packageName), // application package name + encodeURIComponent(productId), // productId + encodeURIComponent(receipt), // purchase token + encodeURIComponent(accessToken) // API access token + ); +}; From 9d1efcbe2f494b91005d95b680515d85c55036c4 Mon Sep 17 00:00:00 2001 From: Antonio Marino Date: Fri, 4 Jan 2019 17:36:22 +0000 Subject: [PATCH 15/21] fix --- lib/google/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/google/index.js b/lib/google/index.js index 3eb0300..8a2c79e 100644 --- a/lib/google/index.js +++ b/lib/google/index.js @@ -143,7 +143,7 @@ exports.cancelSubscription = function (payment, cb) { }; -exports.cancelSubscription = function (payment, deferralInfo, cb) { +exports.deferSubscription = function (payment, deferralInfo, cb) { var keyObject; try { From 3f95fc7c71a55d0a7abb3a0cde457a74a66a4dac Mon Sep 17 00:00:00 2001 From: Antonio Marino Date: Sun, 6 Jan 2019 19:02:11 +0000 Subject: [PATCH 16/21] passing deferralInfo --- lib/google/index.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/google/index.js b/lib/google/index.js index 8a2c79e..d0bba95 100644 --- a/lib/google/index.js +++ b/lib/google/index.js @@ -167,7 +167,12 @@ exports.deferSubscription = function (payment, deferralInfo, cb) { token ); - https.post(requestUrl, null, function (error, res, resultString) { + var options = { + json: { + deferralInfo, + } + } + https.post(requestUrl, options, function (error, res, resultString) { if (error) { return cb(error); } From c3e6c8a6075ecb31e22aed833c36b170115136f1 Mon Sep 17 00:00:00 2001 From: Antonio Marino Date: Sun, 6 Jan 2019 19:32:27 +0000 Subject: [PATCH 17/21] fix lint --- lib/google/index.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/google/index.js b/lib/google/index.js index d0bba95..cc33adc 100644 --- a/lib/google/index.js +++ b/lib/google/index.js @@ -169,9 +169,9 @@ exports.deferSubscription = function (payment, deferralInfo, cb) { var options = { json: { - deferralInfo, + deferralInfo } - } + }; https.post(requestUrl, options, function (error, res, resultString) { if (error) { return cb(error); @@ -181,8 +181,9 @@ exports.deferSubscription = function (payment, deferralInfo, cb) { return cb(new Error('Received ' + res.statusCode + ' status code with body: ' + resultString)); } + var resultObject; try { - var resultObject = JSON.parse(resultString); + resultObject = JSON.parse(resultString); } catch (e) { return cb(e); } From c5ded0c2cb4cb78e68d4a151184d5f480afb154a Mon Sep 17 00:00:00 2001 From: Antonio Marino Date: Mon, 3 Jun 2019 12:53:52 +0100 Subject: [PATCH 18/21] fixed indentation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c95842..654dab9 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,7 @@ be used to extend a user's subscription purchase until a specified future expira ```javascript var deferralInfo = { expectedExpiryTimeMillis: 1546616722237, - desiredExpiryTimeMillis: 1547716722237, + desiredExpiryTimeMillis: 1547716722237, }; iap.deferSubscription("google", payment, deferralInfo, function (error, response) { /* your code */ From 17f9ee5891584bd3ea1f21e2306c455a3093c969 Mon Sep 17 00:00:00 2001 From: VK432 Date: Fri, 15 Nov 2019 00:08:18 +0000 Subject: [PATCH 19/21] google deferral (#1) --- README.md | 3 +-- index.js | 12 ++++++++---- lib/google/index.js | 19 ++++++++++--------- lib/google/urls.js | 3 ++- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 654dab9..46b5575 100644 --- a/README.md +++ b/README.md @@ -87,8 +87,7 @@ iap.cancelSubscription(platform, payment) ### Subscription deferral ( Google Play only ) -Google exposes [an API for deferral](https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/defer) of recurring suscriptions. This might be -be used to extend a user's subscription purchase until a specified future expiration time ( useful to grant your users some free days or months ). +Google exposes [an API for deferral](https://developers.google.com/android-publisher/api-ref/purchases/subscriptions/defer) of recurring suscriptions. This might be used to extend a user's subscription purchase until a specified future expiration time ( useful to grant your users some free days or months ). ```javascript var deferralInfo = { diff --git a/index.js b/index.js index 92d6479..3588888 100644 --- a/index.js +++ b/index.js @@ -96,15 +96,19 @@ exports.deferSubscription = function (platform, payment, deferralInfo, cb) { return syncError(new Error('No payment given')); } - var engine = platforms[platform]; + if (!deferralInfo) { + return syncError(new Error('No deferralInfo given')); + } + + const engine = platforms[platform]; if (!engine) { - return syncError(new Error('Platform ' + platform + ' not recognized')); + return syncError(new Error(`Platform ${platform} not recognized`)); } if (!engine.deferSubscription) { - return syncError(new Error('Platform ' + platform + - ' does not have deferSubscription method')); + return syncError(new Error(`Platform ${platform + } does not have deferSubscription method`)); } engine.deferSubscription(payment, deferralInfo, function (error, result) { diff --git a/lib/google/index.js b/lib/google/index.js index cc33adc..9bc27cd 100644 --- a/lib/google/index.js +++ b/lib/google/index.js @@ -45,7 +45,10 @@ function validateDeferralInfo(deferralInfo) { assert.equal(typeof deferralInfo, 'object', 'deferralInfo must be an object'); assert.equal(typeof deferralInfo.expectedExpiryTimeMillis, 'number', 'expectedExpiryTimeMillis must be a number'); assert.equal(typeof deferralInfo.desiredExpiryTimeMillis, 'number', 'desiredExpiryTimeMillis must be a number'); + assert(deferralInfo.desiredExpiryTimeMillis > deferralInfo.expectedExpiryTimeMillis, 'desiredExpiryTimeMillis must be greater than expectedExpiryTimeMillis'); + + return deferralInfo; } @@ -144,11 +147,14 @@ exports.cancelSubscription = function (payment, cb) { exports.deferSubscription = function (payment, deferralInfo, cb) { - var keyObject; + let keyObject; + let options; try { keyObject = validatePaymentAndParseKeyObject(payment); - validateDeferralInfo(deferralInfo); + options.json = { + deferralInfo: validateDeferralInfo(deferralInfo) + }; } catch (error) { return process.nextTick(function () { cb(error); @@ -160,25 +166,20 @@ exports.deferSubscription = function (payment, deferralInfo, cb) { return cb(error); } - var requestUrl = apiUrls.purchasesSubscriptionsDefer( + const requestUrl = apiUrls.purchasesSubscriptionsDefer( payment.packageName, payment.productId, payment.receipt, token ); - var options = { - json: { - deferralInfo - } - }; https.post(requestUrl, options, function (error, res, resultString) { if (error) { return cb(error); } if (res.statusCode !== 200) { - return cb(new Error('Received ' + res.statusCode + ' status code with body: ' + resultString)); + return cb(new Error(`Received ${res.statusCode} status code with body: ${resultString}`)); } var resultObject; diff --git a/lib/google/urls.js b/lib/google/urls.js index 633be8e..9ca002e 100644 --- a/lib/google/urls.js +++ b/lib/google/urls.js @@ -50,8 +50,9 @@ exports.purchasesSubscriptionsCancel = function (packageName, productId, receipt ); }; +// Android Subscriptions URLs & generators exports.purchasesSubscriptionsDefer = function (packageName, productId, receipt, accessToken) { - var urlFormat = 'https://www.googleapis.com/androidpublisher/v2/applications/%s/purchases/subscriptions/%s/tokens/%s:defer?access_token=%s'; + const urlFormat = 'https://www.googleapis.com/androidpublisher/v3/applications/%s/purchases/subscriptions/%s/tokens/%s:defer?access_token=%s'; return util.format( urlFormat, From c52863e4b315c2b71d70d37e5cc4a6863cee970f Mon Sep 17 00:00:00 2001 From: Antonio Marino Date: Mon, 18 Nov 2019 20:01:22 +0000 Subject: [PATCH 20/21] Bug fix --- lib/google/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/google/index.js b/lib/google/index.js index 9bc27cd..47e1f4c 100644 --- a/lib/google/index.js +++ b/lib/google/index.js @@ -148,7 +148,7 @@ exports.cancelSubscription = function (payment, cb) { exports.deferSubscription = function (payment, deferralInfo, cb) { let keyObject; - let options; + let options = {}; try { keyObject = validatePaymentAndParseKeyObject(payment); From 06412557737822b3ea9e785154b3016125b058bd Mon Sep 17 00:00:00 2001 From: Antonio Marino Date: Tue, 19 Nov 2019 01:28:04 +0000 Subject: [PATCH 21/21] lint fix --- lib/google/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/google/index.js b/lib/google/index.js index 47e1f4c..b669d2d 100644 --- a/lib/google/index.js +++ b/lib/google/index.js @@ -148,7 +148,7 @@ exports.cancelSubscription = function (payment, cb) { exports.deferSubscription = function (payment, deferralInfo, cb) { let keyObject; - let options = {}; + const options = {}; try { keyObject = validatePaymentAndParseKeyObject(payment);