From 47588e7a8d3b2ae2fed0c1e87fdf1ee2db6bcdc2 Mon Sep 17 00:00:00 2001 From: Sebastian Rindom Date: Thu, 24 Feb 2022 20:14:09 +0100 Subject: [PATCH] feat: new tax api (#979) * feat: add tax calculation strategy (#885) * feat: add tax calculation strategy * fix: adds strategy loader * fix: eslint ignore * chore: cleanup * fix: allow plugin overwrites * fix: allow plugin overwrites * fix: fake region * Update packages/medusa/src/loaders/strategies.ts Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> * feat: adds tax related db entities + tax provider (#896) * feat: adds tax related db entities + tax provider * fix: add tax provider tests * fix: add tax service unit tests * fix: tests + migrations * fix: add inherited tax lines * chore: rm tax-line repo * fix: test * fix: pr comments * fix: unit test * feat: totals service to ts (#911) * feat: adds tax related db entities + tax provider * fix: add tax provider tests * fix: add tax service unit tests * fix: tests + migrations * feat: totals service to ts * fix: remove totals.js * fix: add shipping methods * fix: add inherited tax lines * chore: rm tax-line repo * fix: test * fix: tests * fix: tests * fix: unit test * fix: adds TotalsServiceProps * feat: adds integration tests for automatic tax calculation + shipping tax rates (#945) * feat: adds tax related db entities + tax provider * fix: add tax provider tests * fix: add tax service unit tests * fix: tests + migrations * feat: totals service to ts * fix: remove totals.js * fix: add shipping methods * fix: add inherited tax lines * chore: rm tax-line repo * fix: test * fix: tests * fix: tests * fix: unit test * fix: integration test helpers * fix: adds factories + tests automatic tax rates * fix: remove verbose * fix: adds TotalsServiceProps * fix: add shipping tax lines * fix: add migration for shipping taxes * fix: integration tests for shipping taxes * fix: integration tests for shipping taxes * fix: jsdoc types * Feat/manual taxes (#950) * feat: adds tax related db entities + tax provider * fix: add tax provider tests * fix: add tax service unit tests * fix: tests + migrations * feat: totals service to ts * fix: remove totals.js * fix: add shipping methods * fix: add inherited tax lines * chore: rm tax-line repo * fix: test * fix: tests * fix: tests * fix: unit test * fix: integration test helpers * fix: adds factories + tests automatic tax rates * fix: remove verbose * fix: adds TotalsServiceProps * fix: add shipping tax lines * fix: add migration for shipping taxes * fix: integration tests for shipping taxes * fix: integration tests for shipping taxes * fix: add integration tests for manual taxes * fix: cart service - cleanup jsdoc * feat: add /carts/id/taxes to manually calculate taxes * feat: add integration tests for order tax calculations * fix: unit tests * fix: merge * fix: rm verbose * fix: unit tests * fix: object -> cartOrOrder * fix: rounding * Feat/complete order w tax lines (#951) * feat: adds tax related db entities + tax provider * fix: add tax provider tests * fix: add tax service unit tests * fix: tests + migrations * feat: totals service to ts * fix: remove totals.js * fix: add shipping methods * fix: add inherited tax lines * chore: rm tax-line repo * fix: test * fix: tests * fix: tests * fix: unit test * fix: integration test helpers * fix: adds factories + tests automatic tax rates * fix: remove verbose * fix: adds TotalsServiceProps * fix: add shipping tax lines * fix: add migration for shipping taxes * fix: integration tests for shipping taxes * fix: integration tests for shipping taxes * fix: add integration tests for manual taxes * fix: cart service - cleanup jsdoc * feat: add /carts/id/taxes to manually calculate taxes * feat: add integration tests for order tax calculations * feat: adds cart completion strategy + create order w. tax lines * fix: unit tests * fix: merge * fix: rm verbose * fix: unit tests * fix: unit tests * fix: unit tests * fix: ensure calculation for list orders * fix: unit tests * fix: integration tests * fix: adds cart order type gaurds * Docs/tax api (#954) * feat: adds tax related db entities + tax provider * fix: add tax provider tests * fix: add tax service unit tests * fix: tests + migrations * feat: totals service to ts * fix: remove totals.js * fix: add shipping methods * fix: add inherited tax lines * chore: rm tax-line repo * fix: test * fix: tests * fix: tests * fix: unit test * fix: integration test helpers * fix: adds factories + tests automatic tax rates * fix: remove verbose * fix: adds TotalsServiceProps * fix: add shipping tax lines * fix: add migration for shipping taxes * fix: integration tests for shipping taxes * fix: integration tests for shipping taxes * fix: add integration tests for manual taxes * fix: cart service - cleanup jsdoc * feat: add /carts/id/taxes to manually calculate taxes * feat: add integration tests for order tax calculations * feat: adds cart completion strategy + create order w. tax lines * fix: unit tests * fix: merge * fix: rm verbose * fix: unit tests * fix: unit tests * fix: unit tests * fix: ensure calculation for list orders * fix: unit tests * fix: integration tests * docs: documents tax related methods and types * fix: require either item_id or shipping_method_id * feat: product type tax rate (#969) * feat: adds tax related db entities + tax provider * fix: add tax provider tests * fix: add tax service unit tests * fix: tests + migrations * feat: totals service to ts * fix: remove totals.js * fix: add shipping methods * fix: add inherited tax lines * chore: rm tax-line repo * fix: test * fix: tests * fix: tests * fix: unit test * fix: integration test helpers * fix: adds factories + tests automatic tax rates * fix: remove verbose * fix: adds TotalsServiceProps * fix: add shipping tax lines * fix: add migration for shipping taxes * fix: integration tests for shipping taxes * fix: integration tests for shipping taxes * fix: add integration tests for manual taxes * fix: cart service - cleanup jsdoc * feat: add /carts/id/taxes to manually calculate taxes * feat: add integration tests for order tax calculations * feat: adds cart completion strategy + create order w. tax lines * fix: unit tests * fix: merge * fix: rm verbose * fix: unit tests * fix: unit tests * fix: unit tests * fix: ensure calculation for list orders * fix: unit tests * fix: integration tests * docs: documents tax related methods and types * fix: require either item_id or shipping_method_id * feat: adds returns tests for new tax system * feat: adds return lines + integration tests for swaps * feat: return integration tests * feat: adds product type tax rates * feat: add tax management endpoints * fix: create single migration * fix: adds tax rates to js client * fix: strats * Fix/plugin tests (#998) * plugin testing setup * fix: test sendgrid plugin * fix: test sendgrid plugin * chore: clean * chore: clean * fix: clean up tests * fix: remove dirty import * fix: sendgrid + brightpearl * fix: plugin integration tests * fix: klarna * fix: shipping method tax * fix: remove taxrates * fix: unit tests * fix: integration * fix: integration * fix: plugins tests * fix: ignore plugins * fix: tests * fix: taxes (#1017) * fix: taxes * fix: taxes * fix: faulty ref * fix: create tax-lines with claim items * fix: snapshot tax-liens * fix: allows integration test teardown to force deleting tables * fix: tests * fix: merge * fix: adds tax-rates to client * fix: adds tax-rates to medusa-react * fix: tests * fix: tests * fix: add product types * fix: adds tax provider endpoint + cascaded deletes on tax rate relations * fix: move errors to service layer * fix: cleanup api * fix: unit tests * fix: error handler in base-service * fix: Add order region to swap on createFulfillment (#1110) Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com> --- .eslintrc.js | 14 + integration-tests/.babelrc.js | 13 + .../api/__tests__/admin/store.js | 4 +- .../claims/__snapshots__/index.js.snap | 152 + .../api/__tests__/claims/index.js | 272 + .../api/__tests__/returns/index.js | 272 + .../store/__snapshots__/swaps.js.snap | 6 + integration-tests/api/__tests__/store/cart.js | 1 - .../api/__tests__/swaps/index.js | 367 + .../__snapshots__/admin-tax-rates.js.snap | 52 + .../api/__tests__/taxes/admin-tax-rates.js | 526 ++ .../api/__tests__/taxes/automatic-taxes.js | 478 + .../api/__tests__/taxes/manual-taxes.js | 204 + .../api/__tests__/taxes/orders.js | 290 + integration-tests/api/factories/index.ts | 13 + .../api/factories/simple-address-factory.ts | 34 + .../api/factories/simple-cart-factory.ts | 70 + .../api/factories/simple-discount-factory.ts | 55 + .../api/factories/simple-line-item-factory.ts | 84 + .../api/factories/simple-order-factory.ts | 110 + .../api/factories/simple-payment-factory.ts | 43 + .../api/factories/simple-product-factory.ts | 99 + .../simple-product-tax-rate-factory.ts | 48 + .../simple-product-type-tax-rate-factory.ts | 48 + .../simple-product-variant-factory.ts | 64 + .../api/factories/simple-region-factory.ts | 47 + .../simple-shipping-method-factory.ts | 68 + .../simple-shipping-option-factory.ts | 49 + .../simple-shipping-tax-rate-factory.ts | 48 + .../api/factories/simple-tax-rate-factory.ts | 32 + integration-tests/api/package.json | 5 +- .../api/src/services/test-pay.js | 18 +- integration-tests/api/yarn.lock | 75 +- integration-tests/helpers/bootstrap-app.js | 30 + integration-tests/helpers/test-server.js | 29 +- integration-tests/helpers/use-db.js | 10 +- integration-tests/jest.config.js | 1 + integration-tests/package.json | 3 + integration-tests/plugins/.babelrc.js | 13 + integration-tests/plugins/.gitignore | 4 + .../__snapshots__/index.js.snap | 2444 ++++++ .../__tests__/medusa-plugin-sendgrid/index.js | 911 ++ integration-tests/plugins/factories/index.ts | 13 + .../factories/simple-address-factory.ts | 34 + .../plugins/factories/simple-cart-factory.ts | 70 + .../factories/simple-discount-factory.ts | 55 + .../factories/simple-line-item-factory.ts | 84 + .../plugins/factories/simple-order-factory.ts | 110 + .../factories/simple-product-factory.ts | 99 + .../simple-product-tax-rate-factory.ts | 48 + .../simple-product-type-tax-rate-factory.ts | 48 + .../simple-product-variant-factory.ts | 64 + .../factories/simple-region-factory.ts | 47 + .../simple-shipping-method-factory.ts | 68 + .../simple-shipping-option-factory.ts | 49 + .../simple-shipping-tax-rate-factory.ts | 48 + .../plugins/factories/simple-store-factory.ts | 24 + .../factories/simple-tax-rate-factory.ts | 32 + .../plugins/helpers/admin-seeder.js | 18 + .../plugins/helpers/call-helpers.js | 100 + .../plugins/helpers/cart-seeder.js | 536 ++ .../plugins/helpers/claim-seeder.js | 118 + .../plugins/helpers/customer-seeder.js | 33 + .../plugins/helpers/discount-seeder.js | 35 + .../plugins/helpers/draft-order-seeder.js | 261 + .../plugins/helpers/order-seeder.js | 396 + .../plugins/helpers/product-seeder.js | 286 + .../plugins/helpers/shipping-option-seeder.js | 83 + .../plugins/helpers/swap-seeder.js | 434 + .../plugins/helpers/user-seeder.js | 53 + integration-tests/plugins/jest.config.js | 19 + integration-tests/plugins/medusa-config.js | 28 + integration-tests/plugins/package.json | 25 + .../plugins/src/services/test-ful.js | 53 + .../plugins/src/services/test-not.js | 19 + .../plugins/src/services/test-pay.js | 73 + integration-tests/plugins/yarn.lock | 7781 +++++++++++++++++ integration-tests/yarn.lock | 13 + packages/medusa-cli/src/reporter/index.js | 21 +- .../package.json | 1 + .../src/services/webshipper-fulfillment.js | 105 +- .../medusa-js/src/resources/admin/index.ts | 4 + .../medusa-js/src/resources/admin/orders.ts | 62 +- .../src/resources/admin/product-types.ts | 24 + .../medusa-js/src/resources/admin/products.ts | 31 +- .../medusa-js/src/resources/admin/store.ts | 35 +- .../src/resources/admin/tax-rates.ts | 189 + .../src/__mocks__/totals.js | 12 + .../src/services/klarna-provider.js | 120 +- .../src/services/__tests__/brightpearl.js | 84 +- .../src/services/brightpearl.js | 134 +- .../src/subscribers/order.js | 35 +- .../src/services/__tests__/segment.js | 19 +- .../src/services/segment.js | 13 +- .../src/services/sendgrid.js | 501 +- .../src/services/slack.js | 15 +- .../medusa-react/src/hooks/admin/index.ts | 2 + .../src/hooks/admin/product-types/index.ts | 1 + .../src/hooks/admin/product-types/queries.ts | 34 + .../src/hooks/admin/products/queries.ts | 17 - .../src/hooks/admin/store/queries.ts | 22 +- .../src/hooks/admin/tax-rates/index.ts | 2 + .../src/hooks/admin/tax-rates/mutations.ts | 203 + .../src/hooks/admin/tax-rates/queries.ts | 51 + .../test/hooks/admin/products/queries.test.ts | 14 - .../test/hooks/admin/swaps/mutations.test.ts | 2 + packages/medusa/package.json | 1 + packages/medusa/src/api/index.js | 2 + packages/medusa/src/api/routes/admin/index.js | 4 + .../admin/orders/__tests__/get-order.js | 2 + .../api/routes/admin/orders/create-claim.ts | 10 +- .../admin/orders/create-swap-shipment.ts | 2 +- .../api/routes/admin/orders/create-swap.ts | 9 +- .../src/api/routes/admin/orders/index.ts | 11 +- .../api/routes/admin/orders/receive-swap.ts | 95 - .../api/routes/admin/product-types/index.ts | 40 + .../admin/product-types/list-product-types.ts | 125 + .../admin/regions/__tests__/get-region.js | 3 + .../admin/regions/__tests__/list-regions.js | 3 + .../src/api/routes/admin/regions/index.ts | 3 + .../api/routes/admin/regions/update-region.ts | 29 +- .../__tests__/list-shipping-options.js | 4 +- .../routes/admin/shipping-options/index.ts | 4 +- .../shipping-options/list-shipping-options.ts | 4 +- .../src/api/routes/admin/store/index.ts | 10 +- .../routes/admin/store/list-tax-providers.ts | 28 + .../routes/admin/swaps/__tests__/get-swap.js | 6 - .../src/api/routes/admin/swaps/index.ts | 6 - .../admin/tax-rates/add-to-product-types.ts | 66 + .../routes/admin/tax-rates/add-to-products.ts | 63 + .../tax-rates/add-to-shipping-options.ts | 65 + .../routes/admin/tax-rates/create-tax-rate.ts | 114 + .../routes/admin/tax-rates/delete-tax-rate.ts | 40 + .../routes/admin/tax-rates/get-tax-rate.ts | 50 + .../src/api/routes/admin/tax-rates/index.ts | 119 + .../routes/admin/tax-rates/list-tax-rates.ts | 111 + .../tax-rates/remove-from-product-types.ts | 66 + .../admin/tax-rates/remove-from-products.ts | 63 + .../tax-rates/remove-from-shipping-options.ts | 69 + .../routes/admin/tax-rates/update-tax-rate.ts | 116 + .../admin/tax-rates/utils/get-query-config.ts | 78 + .../store/carts/__tests__/complete-cart.js | 107 +- .../api/routes/store/carts/calculate-taxes.ts | 118 + .../api/routes/store/carts/complete-cart.ts | 248 +- .../src/api/routes/store/carts/index.ts | 6 + .../src/api/routes/store/swaps/create-swap.ts | 8 +- packages/medusa/src/helpers/test-request.js | 2 + packages/medusa/src/index.js | 112 +- .../interfaces/cart-completion-strategy.ts | 33 + packages/medusa/src/interfaces/index.ts | 3 + .../interfaces/tax-calculation-strategy.ts | 27 + packages/medusa/src/interfaces/tax-service.ts | 59 + packages/medusa/src/loaders/index.js | 20 +- packages/medusa/src/loaders/models.js | 4 +- packages/medusa/src/loaders/passport.js | 2 +- packages/medusa/src/loaders/plugins.js | 74 +- packages/medusa/src/loaders/services.js | 11 +- packages/medusa/src/loaders/strategies.ts | 37 + .../1641636508055-new_tax_system.ts | 178 + packages/medusa/src/models/cart.ts | 4 +- .../medusa/src/models/line-item-tax-line.ts | 30 + packages/medusa/src/models/line-item.ts | 28 +- packages/medusa/src/models/order.ts | 71 +- .../medusa/src/models/product-tax-rate.ts | 69 + .../src/models/product-type-tax-rate.ts | 68 + packages/medusa/src/models/region.ts | 33 +- .../src/models/shipping-method-tax-line.ts | 30 + packages/medusa/src/models/shipping-method.ts | 12 +- .../medusa/src/models/shipping-tax-rate.ts | 68 + packages/medusa/src/models/swap.ts | 14 +- packages/medusa/src/models/tax-line.ts | 61 + packages/medusa/src/models/tax-provider.ts | 24 + packages/medusa/src/models/tax-rate.ts | 141 + .../src/repositories/line-item-tax-line.ts | 5 + packages/medusa/src/repositories/line-item.ts | 27 +- .../src/repositories/product-tax-rate.ts | 5 + .../repositories/shipping-method-tax-line.ts | 5 + .../src/repositories/shipping-tax-rate.ts | 5 + .../medusa/src/repositories/tax-provider.ts | 5 + packages/medusa/src/repositories/tax-rate.ts | 274 + .../src/services/__mocks__/shipping-option.js | 20 +- .../medusa/src/services/__tests__/cart.js | 2 + .../medusa/src/services/__tests__/claim.js | 43 +- .../medusa/src/services/__tests__/order.js | 96 +- .../medusa/src/services/__tests__/swap.js | 170 +- .../src/services/__tests__/system-tax.js | 85 + .../src/services/__tests__/tax-provider.js | 281 + .../medusa/src/services/__tests__/totals.js | 143 +- packages/medusa/src/services/cart.ts | 346 +- packages/medusa/src/services/claim.js | 122 +- packages/medusa/src/services/fulfillment.js | 2 +- packages/medusa/src/services/index.ts | 3 + packages/medusa/src/services/line-item.js | 48 + packages/medusa/src/services/order.js | 175 +- .../medusa/src/services/product-tax-rate.ts | 60 + packages/medusa/src/services/product-type.ts | 99 + packages/medusa/src/services/region.js | 20 + packages/medusa/src/services/return.js | 61 +- .../medusa/src/services/shipping-option.js | 19 +- .../medusa/src/services/shipping-tax-rate.ts | 61 + packages/medusa/src/services/swap.js | 254 +- packages/medusa/src/services/system-tax.ts | 47 + packages/medusa/src/services/tax-provider.ts | 433 + packages/medusa/src/services/tax-rate.ts | 343 + packages/medusa/src/services/totals.js | 389 - packages/medusa/src/services/totals.ts | 957 ++ .../strategies/__mocks__/cart-completion.js | 14 + .../strategies/__tests__/cart-completion.js | 221 + .../strategies/__tests__/tax-calculation.js | 124 + .../medusa/src/strategies/cart-completion.ts | 294 + .../medusa/src/strategies/tax-calculation.ts | 74 + packages/medusa/src/types/cart.ts | 7 +- packages/medusa/src/types/common.ts | 2 +- packages/medusa/src/types/orders.ts | 6 + packages/medusa/src/types/product-tax-rate.ts | 11 + packages/medusa/src/types/product.ts | 16 + packages/medusa/src/types/request.ts | 3 + .../medusa/src/types/shipping-tax-rate.ts | 11 + packages/medusa/src/types/tax-rate.ts | 33 + packages/medusa/src/types/tax-service.ts | 39 + packages/medusa/src/types/totals.ts | 45 + .../src/utils/format-registration-name.js | 3 + packages/medusa/yarn.lock | 2028 ++++- 223 files changed, 28546 insertions(+), 2229 deletions(-) create mode 100644 integration-tests/.babelrc.js create mode 100644 integration-tests/api/__tests__/claims/__snapshots__/index.js.snap create mode 100644 integration-tests/api/__tests__/claims/index.js create mode 100644 integration-tests/api/__tests__/returns/index.js create mode 100644 integration-tests/api/__tests__/swaps/index.js create mode 100644 integration-tests/api/__tests__/taxes/__snapshots__/admin-tax-rates.js.snap create mode 100644 integration-tests/api/__tests__/taxes/admin-tax-rates.js create mode 100644 integration-tests/api/__tests__/taxes/automatic-taxes.js create mode 100644 integration-tests/api/__tests__/taxes/manual-taxes.js create mode 100644 integration-tests/api/__tests__/taxes/orders.js create mode 100644 integration-tests/api/factories/index.ts create mode 100644 integration-tests/api/factories/simple-address-factory.ts create mode 100644 integration-tests/api/factories/simple-cart-factory.ts create mode 100644 integration-tests/api/factories/simple-discount-factory.ts create mode 100644 integration-tests/api/factories/simple-line-item-factory.ts create mode 100644 integration-tests/api/factories/simple-order-factory.ts create mode 100644 integration-tests/api/factories/simple-payment-factory.ts create mode 100644 integration-tests/api/factories/simple-product-factory.ts create mode 100644 integration-tests/api/factories/simple-product-tax-rate-factory.ts create mode 100644 integration-tests/api/factories/simple-product-type-tax-rate-factory.ts create mode 100644 integration-tests/api/factories/simple-product-variant-factory.ts create mode 100644 integration-tests/api/factories/simple-region-factory.ts create mode 100644 integration-tests/api/factories/simple-shipping-method-factory.ts create mode 100644 integration-tests/api/factories/simple-shipping-option-factory.ts create mode 100644 integration-tests/api/factories/simple-shipping-tax-rate-factory.ts create mode 100644 integration-tests/api/factories/simple-tax-rate-factory.ts create mode 100644 integration-tests/helpers/bootstrap-app.js create mode 100644 integration-tests/plugins/.babelrc.js create mode 100644 integration-tests/plugins/.gitignore create mode 100644 integration-tests/plugins/__tests__/medusa-plugin-sendgrid/__snapshots__/index.js.snap create mode 100644 integration-tests/plugins/__tests__/medusa-plugin-sendgrid/index.js create mode 100644 integration-tests/plugins/factories/index.ts create mode 100644 integration-tests/plugins/factories/simple-address-factory.ts create mode 100644 integration-tests/plugins/factories/simple-cart-factory.ts create mode 100644 integration-tests/plugins/factories/simple-discount-factory.ts create mode 100644 integration-tests/plugins/factories/simple-line-item-factory.ts create mode 100644 integration-tests/plugins/factories/simple-order-factory.ts create mode 100644 integration-tests/plugins/factories/simple-product-factory.ts create mode 100644 integration-tests/plugins/factories/simple-product-tax-rate-factory.ts create mode 100644 integration-tests/plugins/factories/simple-product-type-tax-rate-factory.ts create mode 100644 integration-tests/plugins/factories/simple-product-variant-factory.ts create mode 100644 integration-tests/plugins/factories/simple-region-factory.ts create mode 100644 integration-tests/plugins/factories/simple-shipping-method-factory.ts create mode 100644 integration-tests/plugins/factories/simple-shipping-option-factory.ts create mode 100644 integration-tests/plugins/factories/simple-shipping-tax-rate-factory.ts create mode 100644 integration-tests/plugins/factories/simple-store-factory.ts create mode 100644 integration-tests/plugins/factories/simple-tax-rate-factory.ts create mode 100644 integration-tests/plugins/helpers/admin-seeder.js create mode 100644 integration-tests/plugins/helpers/call-helpers.js create mode 100644 integration-tests/plugins/helpers/cart-seeder.js create mode 100644 integration-tests/plugins/helpers/claim-seeder.js create mode 100644 integration-tests/plugins/helpers/customer-seeder.js create mode 100644 integration-tests/plugins/helpers/discount-seeder.js create mode 100644 integration-tests/plugins/helpers/draft-order-seeder.js create mode 100644 integration-tests/plugins/helpers/order-seeder.js create mode 100644 integration-tests/plugins/helpers/product-seeder.js create mode 100644 integration-tests/plugins/helpers/shipping-option-seeder.js create mode 100644 integration-tests/plugins/helpers/swap-seeder.js create mode 100644 integration-tests/plugins/helpers/user-seeder.js create mode 100644 integration-tests/plugins/jest.config.js create mode 100644 integration-tests/plugins/medusa-config.js create mode 100644 integration-tests/plugins/package.json create mode 100644 integration-tests/plugins/src/services/test-ful.js create mode 100644 integration-tests/plugins/src/services/test-not.js create mode 100644 integration-tests/plugins/src/services/test-pay.js create mode 100644 integration-tests/plugins/yarn.lock create mode 100644 integration-tests/yarn.lock create mode 100644 packages/medusa-js/src/resources/admin/product-types.ts create mode 100644 packages/medusa-js/src/resources/admin/tax-rates.ts create mode 100644 packages/medusa-react/src/hooks/admin/product-types/index.ts create mode 100644 packages/medusa-react/src/hooks/admin/product-types/queries.ts create mode 100644 packages/medusa-react/src/hooks/admin/tax-rates/index.ts create mode 100644 packages/medusa-react/src/hooks/admin/tax-rates/mutations.ts create mode 100644 packages/medusa-react/src/hooks/admin/tax-rates/queries.ts delete mode 100644 packages/medusa/src/api/routes/admin/orders/receive-swap.ts create mode 100644 packages/medusa/src/api/routes/admin/product-types/index.ts create mode 100644 packages/medusa/src/api/routes/admin/product-types/list-product-types.ts create mode 100644 packages/medusa/src/api/routes/admin/store/list-tax-providers.ts create mode 100644 packages/medusa/src/api/routes/admin/tax-rates/add-to-product-types.ts create mode 100644 packages/medusa/src/api/routes/admin/tax-rates/add-to-products.ts create mode 100644 packages/medusa/src/api/routes/admin/tax-rates/add-to-shipping-options.ts create mode 100644 packages/medusa/src/api/routes/admin/tax-rates/create-tax-rate.ts create mode 100644 packages/medusa/src/api/routes/admin/tax-rates/delete-tax-rate.ts create mode 100644 packages/medusa/src/api/routes/admin/tax-rates/get-tax-rate.ts create mode 100644 packages/medusa/src/api/routes/admin/tax-rates/index.ts create mode 100644 packages/medusa/src/api/routes/admin/tax-rates/list-tax-rates.ts create mode 100644 packages/medusa/src/api/routes/admin/tax-rates/remove-from-product-types.ts create mode 100644 packages/medusa/src/api/routes/admin/tax-rates/remove-from-products.ts create mode 100644 packages/medusa/src/api/routes/admin/tax-rates/remove-from-shipping-options.ts create mode 100644 packages/medusa/src/api/routes/admin/tax-rates/update-tax-rate.ts create mode 100644 packages/medusa/src/api/routes/admin/tax-rates/utils/get-query-config.ts create mode 100644 packages/medusa/src/api/routes/store/carts/calculate-taxes.ts create mode 100644 packages/medusa/src/interfaces/cart-completion-strategy.ts create mode 100644 packages/medusa/src/interfaces/index.ts create mode 100644 packages/medusa/src/interfaces/tax-calculation-strategy.ts create mode 100644 packages/medusa/src/interfaces/tax-service.ts create mode 100644 packages/medusa/src/loaders/strategies.ts create mode 100644 packages/medusa/src/migrations/1641636508055-new_tax_system.ts create mode 100644 packages/medusa/src/models/line-item-tax-line.ts create mode 100644 packages/medusa/src/models/product-tax-rate.ts create mode 100644 packages/medusa/src/models/product-type-tax-rate.ts create mode 100644 packages/medusa/src/models/shipping-method-tax-line.ts create mode 100644 packages/medusa/src/models/shipping-tax-rate.ts create mode 100644 packages/medusa/src/models/tax-line.ts create mode 100644 packages/medusa/src/models/tax-provider.ts create mode 100644 packages/medusa/src/models/tax-rate.ts create mode 100644 packages/medusa/src/repositories/line-item-tax-line.ts create mode 100644 packages/medusa/src/repositories/product-tax-rate.ts create mode 100644 packages/medusa/src/repositories/shipping-method-tax-line.ts create mode 100644 packages/medusa/src/repositories/shipping-tax-rate.ts create mode 100644 packages/medusa/src/repositories/tax-provider.ts create mode 100644 packages/medusa/src/repositories/tax-rate.ts create mode 100644 packages/medusa/src/services/__tests__/system-tax.js create mode 100644 packages/medusa/src/services/__tests__/tax-provider.js create mode 100644 packages/medusa/src/services/product-tax-rate.ts create mode 100644 packages/medusa/src/services/product-type.ts create mode 100644 packages/medusa/src/services/shipping-tax-rate.ts create mode 100644 packages/medusa/src/services/system-tax.ts create mode 100644 packages/medusa/src/services/tax-provider.ts create mode 100644 packages/medusa/src/services/tax-rate.ts delete mode 100644 packages/medusa/src/services/totals.js create mode 100644 packages/medusa/src/services/totals.ts create mode 100644 packages/medusa/src/strategies/__mocks__/cart-completion.js create mode 100644 packages/medusa/src/strategies/__tests__/cart-completion.js create mode 100644 packages/medusa/src/strategies/__tests__/tax-calculation.js create mode 100644 packages/medusa/src/strategies/cart-completion.ts create mode 100644 packages/medusa/src/strategies/tax-calculation.ts create mode 100644 packages/medusa/src/types/product-tax-rate.ts create mode 100644 packages/medusa/src/types/request.ts create mode 100644 packages/medusa/src/types/shipping-tax-rate.ts create mode 100644 packages/medusa/src/types/tax-rate.ts create mode 100644 packages/medusa/src/types/tax-service.ts create mode 100644 packages/medusa/src/types/totals.ts diff --git a/.eslintrc.js b/.eslintrc.js index 9d33c15205..ee070ed040 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -31,6 +31,20 @@ module.exports = { plugins: [`@typescript-eslint/eslint-plugin`], extends: [`plugin:@typescript-eslint/recommended`], rules: { + "valid-jsdoc": [ + "error", + { + requireParamType: false, + requireReturnType: false, + prefer: { + arg: "param", + argument: "param", + class: "constructor", + return: "return", + virtual: "abstract", + }, + }, + ], "@typescript-eslint/explicit-function-return-type": ["error"], "@typescript-eslint/no-non-null-assertion": ["off"], }, diff --git a/integration-tests/.babelrc.js b/integration-tests/.babelrc.js new file mode 100644 index 0000000000..bde709c495 --- /dev/null +++ b/integration-tests/.babelrc.js @@ -0,0 +1,13 @@ +let ignore = [`**/dist`] + +// Jest needs to compile this code, but generally we don't want this copied +// to output folders +if (process.env.NODE_ENV !== `test`) { + ignore.push(`**/__tests__`) +} + +module.exports = { + sourceMaps: true, + presets: ["babel-preset-medusa-package"], + ignore, +} diff --git a/integration-tests/api/__tests__/admin/store.js b/integration-tests/api/__tests__/admin/store.js index 6b0fbea9f9..fca3c7a244 100644 --- a/integration-tests/api/__tests__/admin/store.js +++ b/integration-tests/api/__tests__/admin/store.js @@ -75,8 +75,8 @@ describe("/admin/store", () => { afterEach(async () => { const db = useDb() - await db.teardown() - medusaProcess.kill() + await db.teardown({ forceDelete: ["store"] }) + await medusaProcess.kill() }) it("fails to update default currency if not in store currencies", async () => { diff --git a/integration-tests/api/__tests__/claims/__snapshots__/index.js.snap b/integration-tests/api/__tests__/claims/__snapshots__/index.js.snap new file mode 100644 index 0000000000..29f15a80d2 --- /dev/null +++ b/integration-tests/api/__tests__/claims/__snapshots__/index.js.snap @@ -0,0 +1,152 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Claims creates a refund claim 1`] = ` +Object { + "additional_items": Array [], + "canceled_at": null, + "claim_items": ArrayContaining [ + ObjectContaining { + "item": Any, + "item_id": "test-item", + "quantity": 1, + }, + ], + "created_at": Any, + "deleted_at": null, + "fulfillment_status": "not_fulfilled", + "fulfillments": Array [], + "id": StringMatching /\\^claim_\\*/, + "idempotency_key": Any, + "metadata": null, + "no_notification": null, + "order_id": Any, + "payment_status": "refunded", + "refund_amount": 1200, + "return_order": null, + "shipping_address": Any, + "shipping_address_id": Any, + "shipping_methods": Array [], + "type": "refund", + "updated_at": Any, +} +`; + +exports[`Claims creates a replace claim 1`] = ` +Object { + "additional_items": Array [ + Object { + "allow_discounts": true, + "cart_id": null, + "claim_order_id": StringMatching /\\^claim_\\*/, + "created_at": Any, + "description": "Practical Granite Pizza", + "fulfilled_quantity": null, + "has_shipping": null, + "id": StringMatching /\\^item_\\*/, + "is_giftcard": false, + "is_return": false, + "metadata": Object {}, + "order_id": null, + "quantity": 1, + "refundable": 113, + "returned_quantity": null, + "shipped_quantity": null, + "should_merge": true, + "swap_id": null, + "tax_lines": Array [ + Object { + "code": "default", + "created_at": Any, + "id": StringMatching /\\^litl_\\*/, + "item_id": StringMatching /\\^item_\\*/, + "metadata": null, + "name": "default", + "rate": 12.5, + "updated_at": Any, + }, + ], + "thumbnail": null, + "title": "Awesome Metal Ball", + "unit_price": 100, + "updated_at": Any, + "variant": Object { + "allow_backorder": false, + "barcode": null, + "created_at": Any, + "deleted_at": null, + "ean": null, + "height": null, + "hs_code": null, + "id": "test-variant", + "inventory_quantity": 9, + "length": null, + "manage_inventory": true, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "product": Object { + "collection_id": null, + "created_at": Any, + "deleted_at": null, + "description": null, + "discountable": true, + "external_id": null, + "handle": null, + "height": null, + "hs_code": null, + "id": "test-product", + "is_giftcard": false, + "length": null, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "profile_id": StringMatching /\\^sp_\\*/, + "status": "draft", + "subtitle": null, + "thumbnail": null, + "title": "Awesome Metal Ball", + "type_id": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "product_id": "test-product", + "sku": null, + "title": "Practical Granite Pizza", + "upc": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "variant_id": "test-variant", + }, + ], + "canceled_at": null, + "claim_items": ArrayContaining [ + ObjectContaining { + "item": Any, + "item_id": "test-item", + "quantity": 1, + }, + ], + "created_at": Any, + "deleted_at": null, + "fulfillment_status": "not_fulfilled", + "fulfillments": Array [], + "id": StringMatching /\\^claim_\\*/, + "idempotency_key": Any, + "metadata": null, + "no_notification": null, + "order_id": Any, + "payment_status": "na", + "refund_amount": null, + "return_order": null, + "shipping_address": Any, + "shipping_address_id": Any, + "shipping_methods": Array [], + "type": "replace", + "updated_at": Any, +} +`; diff --git a/integration-tests/api/__tests__/claims/index.js b/integration-tests/api/__tests__/claims/index.js new file mode 100644 index 0000000000..d7bfaed911 --- /dev/null +++ b/integration-tests/api/__tests__/claims/index.js @@ -0,0 +1,272 @@ +const path = require("path") + +const setupServer = require("../../../helpers/setup-server") +const { useApi } = require("../../../helpers/use-api") +const { initDb, useDb } = require("../../../helpers/use-db") + +const adminSeeder = require("../../helpers/admin-seeder") + +const { + simpleOrderFactory, + simpleShippingOptionFactory, + simplePaymentFactory, + simpleProductFactory, +} = require("../../factories") + +describe("Claims", () => { + let medusaProcess + let dbConnection + + const doAfterEach = async () => { + const db = useDb() + return await db.teardown() + } + + beforeAll(async () => { + const cwd = path.resolve(path.join(__dirname, "..", "..")) + try { + dbConnection = await initDb({ cwd }) + medusaProcess = await setupServer({ cwd }) + } catch (error) { + console.log(error) + } + }) + + afterAll(async () => { + const db = useDb() + await db.shutdown() + medusaProcess.kill() + }) + + afterEach(async () => { + return await doAfterEach() + }) + + test("creates a refund claim", async () => { + await adminSeeder(dbConnection) + + const order = await createReturnableOrder(dbConnection) + const api = useApi() + + const response = await api.post( + `/admin/orders/${order.id}/claims`, + { + type: "refund", + claim_items: [ + { + item_id: "test-item", + reason: "missing_item", + quantity: 1, + }, + ], + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + expect(response.data.order.claims[0]).toMatchSnapshot({ + id: expect.stringMatching(/^claim_*/), + order_id: expect.any(String), + updated_at: expect.any(String), + created_at: expect.any(String), + idempotency_key: expect.any(String), + shipping_address_id: expect.any(String), + refund_amount: 1200, + shipping_address: expect.any(Object), + claim_items: expect.arrayContaining([ + expect.objectContaining({ + item: expect.any(Object), + item_id: "test-item", + quantity: 1, + }), + ]), + }) + }) + + test("creates a replace claim", async () => { + await adminSeeder(dbConnection) + + const order = await createReturnableOrder(dbConnection) + const api = useApi() + + const response = await api.post( + `/admin/orders/${order.id}/claims`, + { + type: "replace", + additional_items: [{ variant_id: "test-variant", quantity: 1 }], + claim_items: [ + { + item_id: "test-item", + reason: "missing_item", + quantity: 1, + }, + ], + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + expect(response.data.order.claims[0]).toMatchSnapshot({ + id: expect.stringMatching(/^claim_*/), + order_id: expect.any(String), + updated_at: expect.any(String), + created_at: expect.any(String), + idempotency_key: expect.any(String), + shipping_address_id: expect.any(String), + refund_amount: null, + shipping_address: expect.any(Object), + additional_items: [ + { + id: expect.stringMatching(/^item_*/), + claim_order_id: expect.stringMatching(/^claim_*/), + created_at: expect.any(String), + updated_at: expect.any(String), + variant: { + created_at: expect.any(String), + updated_at: expect.any(String), + product: { + profile_id: expect.stringMatching(/^sp_*/), + created_at: expect.any(String), + updated_at: expect.any(String), + }, + }, + tax_lines: [ + { + id: expect.stringMatching(/^litl_*/), + item_id: expect.stringMatching(/^item_*/), + created_at: expect.any(String), + updated_at: expect.any(String), + rate: 12.5, + }, + ], + }, + ], + claim_items: expect.arrayContaining([ + expect.objectContaining({ + item: expect.any(Object), + item_id: "test-item", + quantity: 1, + }), + ]), + }) + }) + + test("creates a replace claim fulfillment", async () => { + await adminSeeder(dbConnection) + + const order = await createReturnableOrder(dbConnection) + const option = await simpleShippingOptionFactory(dbConnection, { + region_id: "test-region", + }) + const api = useApi() + + const createRes = await api.post( + `/admin/orders/${order.id}/claims`, + { + type: "replace", + shipping_methods: [ + { + option_id: option.id, + price: 0, + }, + ], + additional_items: [{ variant_id: "test-variant", quantity: 1 }], + claim_items: [ + { + item_id: "test-item", + reason: "missing_item", + quantity: 1, + }, + ], + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + const response = await api.post( + `/admin/orders/${order.id}/claims/${createRes.data.order.claims[0].id}/fulfillments`, + {}, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + }) +}) + +const createReturnableOrder = async (dbConnection, options = {}) => { + await simpleProductFactory( + dbConnection, + { + id: "test-product", + variants: [ + { id: "test-variant" }, + { id: "variant-2", prices: [{ currency: "usd", amount: 1000 }] }, + ], + }, + 100 + ) + + let discounts = [] + + if (options.discount) { + discounts = [ + { + code: "TESTCODE", + }, + ] + } + + const order = await simpleOrderFactory(dbConnection, { + email: "test@testson.com", + tax_rate: null, + fulfillment_status: "fulfilled", + payment_status: "captured", + region: { + id: "test-region", + name: "Test region", + tax_rate: 12.5, // Should be ignored due to item tax line + }, + discounts, + line_items: [ + { + id: "test-item", + variant_id: "test-variant", + quantity: 2, + fulfilled_quantity: 2, + shipped_quantity: 2, + unit_price: 1000, + tax_lines: [ + { + name: "default", + code: "default", + rate: 20, + }, + ], + }, + ], + }) + + await simplePaymentFactory(dbConnection, { + provider_id: "test-pay", + order: order.id, + amount: 2400, + captured: true, + }) + + return order +} diff --git a/integration-tests/api/__tests__/returns/index.js b/integration-tests/api/__tests__/returns/index.js new file mode 100644 index 0000000000..5ae7a451ef --- /dev/null +++ b/integration-tests/api/__tests__/returns/index.js @@ -0,0 +1,272 @@ +const path = require("path") + +const setupServer = require("../../../helpers/setup-server") +const { useApi } = require("../../../helpers/use-api") +const { initDb, useDb } = require("../../../helpers/use-db") + +const adminSeeder = require("../../helpers/admin-seeder") + +const { + simpleOrderFactory, + simpleProductFactory, + simpleShippingOptionFactory, +} = require("../../factories") + +describe("/admin/orders", () => { + let medusaProcess + let dbConnection + + const doAfterEach = async () => { + const db = useDb() + return await db.teardown() + } + + beforeAll(async () => { + const cwd = path.resolve(path.join(__dirname, "..", "..")) + try { + dbConnection = await initDb({ cwd }) + medusaProcess = await setupServer({ cwd }) + } catch (error) { + console.log(error) + } + }) + + afterAll(async () => { + const db = useDb() + await db.shutdown() + medusaProcess.kill() + }) + + afterEach(async () => { + return await doAfterEach() + }) + + test("creates a return w. old tax system", async () => { + await adminSeeder(dbConnection) + + const order = await createReturnableOrder(dbConnection, { oldTaxes: true }) + const api = useApi() + + const response = await api.post( + `/admin/orders/${order.id}/return`, + { + items: [ + { + item_id: "test-item", + quantity: 1, + note: "TOO SMALL", + }, + ], + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + + /* + * Region has default tax rate 12.5 therefore refund amount should be + * 1000 * 1.125 = 1125 + */ + expect(response.data.order.returns[0].refund_amount).toEqual(1125) + expect(response.data.order.returns[0].items).toEqual([ + expect.objectContaining({ + item_id: "test-item", + quantity: 1, + note: "TOO SMALL", + }), + ]) + }) + + test("creates a return w. new tax system", async () => { + await adminSeeder(dbConnection) + const order = await createReturnableOrder(dbConnection, { oldTaxes: false }) + + const api = useApi() + + const response = await api.post( + `/admin/orders/${order.id}/return`, + { + items: [ + { + item_id: "test-item", + quantity: 1, + note: "TOO SMALL", + }, + ], + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + + /* + * Region has default tax rate 12.5 but line item has tax rate 20 + * therefore refund amount should be 1000 * 1.2 = 1200 + */ + expect(response.data.order.returns[0].refund_amount).toEqual(1200) + + expect(response.data.order.returns[0].items).toEqual([ + expect.objectContaining({ + item_id: "test-item", + quantity: 1, + note: "TOO SMALL", + }), + ]) + }) + + test("creates a return w. new tax system + shipping", async () => { + await adminSeeder(dbConnection) + const order = await createReturnableOrder(dbConnection, { oldTaxes: false }) + const returnOption = await simpleShippingOptionFactory(dbConnection, { + name: "Return method", + region_id: "test-region", + is_return: true, + price: 1000, + }) + + const api = useApi() + + const response = await api.post( + `/admin/orders/${order.id}/return`, + { + return_shipping: { + option_id: returnOption.id, + }, + items: [ + { + item_id: "test-item", + quantity: 1, + note: "TOO SMALL", + }, + ], + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + + /* + * Region has default tax rate 12.5 but line item has tax rate 20 + * therefore refund amount should be 1000 * 1.2 = 1200 + * shipping method will have 12.5 rate 1000 * 1.125 = 1125 + */ + expect(response.data.order.returns[0].refund_amount).toEqual(75) + expect(response.data.order.returns[0].shipping_method.tax_lines).toEqual([ + expect.objectContaining({ + rate: 12.5, + name: "default", + code: "default", + }), + ]) + expect(response.data.order.returns[0].items).toEqual([ + expect.objectContaining({ + item_id: "test-item", + quantity: 1, + note: "TOO SMALL", + }), + ]) + }) + + test("creates a return w. discount", async () => { + await adminSeeder(dbConnection) + const order = await createReturnableOrder(dbConnection, { + discount: true, + oldTaxes: false, + }) + + const api = useApi() + + const response = await api.post( + `/admin/orders/${order.id}/return`, + { + items: [ + { + item_id: "test-item", + quantity: 1, + note: "TOO SMALL", + }, + ], + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + + /* + * Region has default tax rate 12.5 but line item has tax rate 20 + * therefore refund amount should be 1000 - 100 * 1.2 = 1080 + */ + expect(response.data.order.returns[0].refund_amount).toEqual(1080) + + expect(response.data.order.returns[0].items).toEqual([ + expect.objectContaining({ + item_id: "test-item", + quantity: 1, + note: "TOO SMALL", + }), + ]) + }) +}) + +const createReturnableOrder = async (dbConnection, options) => { + await simpleProductFactory( + dbConnection, + { + id: "test-product", + variants: [{ id: "test-variant" }], + }, + 100 + ) + + let discounts = [] + + if (options.discount) { + discounts = [ + { + code: "TESTCODE", + }, + ] + } + + return await simpleOrderFactory(dbConnection, { + email: "test@testson.com", + tax_rate: options.oldTaxes ? undefined : null, + region: { + id: "test-region", + name: "Test region", + tax_rate: 12.5, // Should be ignored due to item tax line + }, + discounts, + line_items: [ + { + id: "test-item", + variant_id: "test-variant", + quantity: 2, + unit_price: 1000, + tax_lines: [ + { + name: "default", + code: "default", + rate: 20, + }, + ], + }, + ], + }) +} diff --git a/integration-tests/api/__tests__/store/__snapshots__/swaps.js.snap b/integration-tests/api/__tests__/store/__snapshots__/swaps.js.snap index c0fc566bff..5605ac2735 100644 --- a/integration-tests/api/__tests__/store/__snapshots__/swaps.js.snap +++ b/integration-tests/api/__tests__/store/__snapshots__/swaps.js.snap @@ -14,6 +14,7 @@ Object { "has_shipping": null, "id": StringMatching /\\^item_\\*/, "is_giftcard": false, + "is_return": false, "metadata": Object {}, "order_id": null, "quantity": 1, @@ -93,6 +94,7 @@ Object { "parent_order_id": "test-order", "swap_id": StringMatching /\\^swap_\\*/, }, + "object": "cart", "payment_authorized_at": null, "payment_id": null, "region_id": "test-region", @@ -126,6 +128,7 @@ Object { "idempotency_key": null, "metadata": null, "no_notification": null, + "object": "order", "payment_status": "captured", "region_id": "test-region", "shipping_address_id": "test-shipping-address", @@ -187,6 +190,7 @@ Object { "has_shipping": null, "id": StringMatching /\\^item_\\*/, "is_giftcard": false, + "is_return": false, "metadata": Object {}, "order_id": null, "quantity": 1, @@ -266,6 +270,7 @@ Object { "parent_order_id": "test-order", "swap_id": StringMatching /\\^swap_\\*/, }, + "object": "cart", "payment_authorized_at": null, "payment_id": null, "region_id": "test-region", @@ -299,6 +304,7 @@ Object { "idempotency_key": null, "metadata": null, "no_notification": null, + "object": "order", "payment_status": "captured", "region_id": "test-region", "shipping_address_id": "test-shipping-address", diff --git a/integration-tests/api/__tests__/store/cart.js b/integration-tests/api/__tests__/store/cart.js index ab9fb24d3b..f4e2f068c0 100644 --- a/integration-tests/api/__tests__/store/cart.js +++ b/integration-tests/api/__tests__/store/cart.js @@ -5,7 +5,6 @@ const { GiftCard, Cart, CustomShippingOption, - ShippingOption, } = require("@medusajs/medusa") const setupServer = require("../../../helpers/setup-server") diff --git a/integration-tests/api/__tests__/swaps/index.js b/integration-tests/api/__tests__/swaps/index.js new file mode 100644 index 0000000000..82ca8da79b --- /dev/null +++ b/integration-tests/api/__tests__/swaps/index.js @@ -0,0 +1,367 @@ +const path = require("path") + +const setupServer = require("../../../helpers/setup-server") +const { useApi } = require("../../../helpers/use-api") +const { initDb, useDb } = require("../../../helpers/use-db") + +const adminSeeder = require("../../helpers/admin-seeder") + +const { + simpleOrderFactory, + simpleShippingOptionFactory, + simpleProductFactory, +} = require("../../factories") + +describe("Swaps", () => { + let medusaProcess + let dbConnection + + const doAfterEach = async () => { + const db = useDb() + return await db.teardown() + } + + beforeAll(async () => { + const cwd = path.resolve(path.join(__dirname, "..", "..")) + try { + dbConnection = await initDb({ cwd }) + medusaProcess = await setupServer({ cwd }) + } catch (error) { + console.log(error) + } + }) + + afterAll(async () => { + const db = useDb() + await db.shutdown() + medusaProcess.kill() + }) + + afterEach(async () => { + return await doAfterEach() + }) + + test("creates a swap", async () => { + await adminSeeder(dbConnection) + + const order = await createReturnableOrder(dbConnection) + const api = useApi() + + const response = await api.post( + `/admin/orders/${order.id}/swaps`, + { + additional_items: [ + { + variant_id: "variant-2", + quantity: 1, + }, + ], + return_items: [ + { + item_id: "test-item", + quantity: 1, + }, + ], + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + + const cartId = response.data.order.swaps[0].cart_id + + /* + * The return line item should use its tax_lines; the new line doesn't have + * a tax line and uses the default region tax of 12.5 + * + * Return line: 1000 * 1.2 = -1200 + * New line: 1000 * 1.125 = 1125 + * - + * Difference should be -75 + */ + const cartRes = await api.get(`/store/carts/${cartId}`) + expect(cartRes.status).toEqual(200) + expect(cartRes.data.cart.subtotal).toEqual(0) + expect(cartRes.data.cart.total).toEqual(-75) + expect(cartRes.data.cart.tax_total).toEqual(-75) + }) + + test("creates a swap w. shipping", async () => { + await adminSeeder(dbConnection) + + const order = await createReturnableOrder(dbConnection) + const returnOption = await simpleShippingOptionFactory(dbConnection, { + name: "Return method", + region_id: "test-region", + is_return: true, + price: 100, + }) + + const api = useApi() + + const response = await api.post( + `/admin/orders/${order.id}/swaps`, + { + additional_items: [ + { + variant_id: "variant-2", + quantity: 1, + }, + ], + return_shipping: { + option_id: returnOption.id, + }, + return_items: [ + { + item_id: "test-item", + quantity: 1, + }, + ], + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + + const cartId = response.data.order.swaps[0].cart_id + + /* + * The return line item should use its tax_lines; the new line doesn't have + * a tax line and uses the default region tax of 12.5 + * + * Return line: 1000 * 1.2 = -1200 + * New line: 1000 * 1.125 = 1125 + * Shipping line: 100 * 1.125 = 112.5 ~ 113 + * - + * Difference should be 38 + */ + const cartRes = await api.get(`/store/carts/${cartId}`) + expect(cartRes.status).toEqual(200) + expect(cartRes.data.cart.subtotal).toEqual(100) + expect(cartRes.data.cart.tax_total).toEqual(-62) + expect(cartRes.data.cart.total).toEqual(38) + }) + + test("retrieves a swap w. shipping", async () => { + await adminSeeder(dbConnection) + + const order = await createReturnableOrder(dbConnection) + const returnOption = await simpleShippingOptionFactory(dbConnection, { + name: "Return method", + region_id: "test-region", + is_return: true, + price: 100, + }) + + const api = useApi() + + const response = await api.post( + `/admin/orders/${order.id}/swaps`, + { + additional_items: [ + { + variant_id: "variant-2", + quantity: 1, + }, + ], + return_shipping: { + option_id: returnOption.id, + }, + return_items: [ + { + item_id: "test-item", + quantity: 1, + }, + ], + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + + const swapRes = await api.get( + `/admin/swaps/${response.data.order.swaps[0].id}`, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + expect(swapRes.status).toEqual(200) + expect(swapRes.data.swap.cart.subtotal).toEqual(100) + expect(swapRes.data.swap.cart.tax_total).toEqual(-62) + expect(swapRes.data.swap.cart.total).toEqual(38) + }) + + test("creates a swap from storefront", async () => { + const order = await createReturnableOrder(dbConnection) + const api = useApi() + + const response = await api.post(`/store/swaps`, { + order_id: order.id, + additional_items: [ + { + variant_id: "variant-2", + quantity: 1, + }, + ], + return_items: [ + { + item_id: "test-item", + quantity: 1, + }, + ], + }) + + expect(response.status).toEqual(200) + + const cartId = response.data.swap.cart_id + + /* + * The return line item should use its tax_lines; the new line doesn't have + * a tax line and uses the default region tax of 12.5 + * + * Return line: 1000 * 1.2 = -1200 + * New line: 1000 * 1.125 = 1125 + * - + * Difference should be -75 + */ + const cartRes = await api.get(`/store/carts/${cartId}`) + expect(cartRes.status).toEqual(200) + expect(cartRes.data.cart.subtotal).toEqual(0) + expect(cartRes.data.cart.total).toEqual(-75) + expect(cartRes.data.cart.tax_total).toEqual(-75) + }) + + test("completes a swap", async () => { + await adminSeeder(dbConnection) + + const order = await createReturnableOrder(dbConnection) + const shippingOut = await simpleShippingOptionFactory(dbConnection, { + region_id: "test-region", + price: 500, + }) + const returnOption = await simpleShippingOptionFactory(dbConnection, { + name: "Return method", + region_id: "test-region", + is_return: true, + price: 100, + }) + + const api = useApi() + + const response = await api.post( + `/admin/orders/${order.id}/swaps`, + { + additional_items: [ + { + variant_id: "variant-2", + quantity: 1, + }, + ], + return_shipping: { + option_id: returnOption.id, + }, + return_items: [ + { + item_id: "test-item", + quantity: 1, + }, + ], + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + + const cartId = response.data.order.swaps[0].cart_id + + await api.post(`/store/carts/${cartId}`, { + shipping_address: { + address_1: "121 W Something St", + postal_code: "1234", + province: "something", + city: "ville la something", + phone: "12353245", + }, + }) + await api.post(`/store/carts/${cartId}/shipping-methods`, { + option_id: shippingOut.id, + }) + await api.post(`/store/carts/${cartId}/payment-sessions`) + const completion = await api.post(`/store/carts/${cartId}/complete`) + + expect(completion.status).toEqual(200) + expect(completion.data.type).toEqual("swap") + }) +}) + +const createReturnableOrder = async (dbConnection, options = {}) => { + await simpleProductFactory( + dbConnection, + { + id: "test-product", + variants: [ + { id: "test-variant" }, + { id: "variant-2", prices: [{ currency: "usd", amount: 1000 }] }, + ], + }, + 100 + ) + + let discounts = [] + + if (options.discount) { + discounts = [ + { + code: "TESTCODE", + }, + ] + } + + return await simpleOrderFactory(dbConnection, { + email: "test@testson.com", + tax_rate: null, + fulfillment_status: "fulfilled", + payment_status: "captured", + region: { + id: "test-region", + name: "Test region", + tax_rate: 12.5, // Should be ignored due to item tax line + }, + discounts, + line_items: [ + { + id: "test-item", + variant_id: "test-variant", + quantity: 2, + fulfilled_quantity: 2, + shipped_quantity: 2, + unit_price: 1000, + tax_lines: [ + { + name: "default", + code: "default", + rate: 20, + }, + ], + }, + ], + }) +} diff --git a/integration-tests/api/__tests__/taxes/__snapshots__/admin-tax-rates.js.snap b/integration-tests/api/__tests__/taxes/__snapshots__/admin-tax-rates.js.snap new file mode 100644 index 0000000000..196fc06eed --- /dev/null +++ b/integration-tests/api/__tests__/taxes/__snapshots__/admin-tax-rates.js.snap @@ -0,0 +1,52 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`/admin/tax-rates creates a tax rate 1`] = ` +Object { + "code": "tricks", + "created_at": Any, + "id": StringMatching /\\^txr_\\*/, + "name": "special", + "rate": null, + "region_id": "test-region", + "updated_at": Any, +} +`; + +exports[`/admin/tax-rates deletes a tax rate 1`] = ` +Object { + "deleted": true, + "id": StringMatching /\\^txr_\\*/, + "object": "tax-rate", +} +`; + +exports[`/admin/tax-rates get tax rates 1`] = ` +Object { + "code": "Bedfordshire", + "created_at": Any, + "id": StringMatching /\\^txr_\\*/, + "name": "Market Island", + "rate": 96, + "region_id": Any, + "updated_at": Any, +} +`; + +exports[`/admin/tax-rates get tax rates w. fields 1`] = ` +Object { + "id": StringMatching /\\^txr_\\*/, + "region_id": Any, +} +`; + +exports[`/admin/tax-rates updates a tax rate 1`] = ` +Object { + "code": "something new", + "created_at": Any, + "id": StringMatching /\\^txr_\\*/, + "name": "special", + "rate": 10, + "region_id": "test-region", + "updated_at": Any, +} +`; diff --git a/integration-tests/api/__tests__/taxes/admin-tax-rates.js b/integration-tests/api/__tests__/taxes/admin-tax-rates.js new file mode 100644 index 0000000000..0303c7ba56 --- /dev/null +++ b/integration-tests/api/__tests__/taxes/admin-tax-rates.js @@ -0,0 +1,526 @@ +const path = require("path") + +const setupServer = require("../../../helpers/setup-server") +const { useApi } = require("../../../helpers/use-api") +const { initDb, useDb } = require("../../../helpers/use-db") + +const adminSeeder = require("../../helpers/admin-seeder") + +const { + simpleProductFactory, + simpleShippingOptionFactory, + simpleRegionFactory, + simpleTaxRateFactory, +} = require("../../factories") + +jest.setTimeout(30000) + +describe("/admin/tax-rates", () => { + let medusaProcess + let dbConnection + + const doAfterEach = async () => { + const db = useDb() + return await db.teardown() + } + + beforeAll(async () => { + const cwd = path.resolve(path.join(__dirname, "..", "..")) + try { + dbConnection = await initDb({ cwd }) + medusaProcess = await setupServer({ cwd, verbose: true }) + } catch (error) { + console.log(error) + } + }) + + afterAll(async () => { + const db = useDb() + await db.shutdown() + medusaProcess.kill() + }) + + afterEach(async () => { + return await doAfterEach() + }) + + test("list tax rates", async () => { + await adminSeeder(dbConnection) + await createTaxRates(dbConnection, 20, 2, 200) + + const api = useApi() + + const response = await api.get("/admin/tax-rates", { + headers: { + authorization: "Bearer test_token", + }, + }) + + expect(response.status).toEqual(200) + expect(response.data.count).toEqual(20) + }) + + test("list tax rates w. query", async () => { + await adminSeeder(dbConnection) + await createTaxRates(dbConnection, 20, 2, 200) + + const api = useApi() + + const response = await api.get( + `/admin/tax-rates?fields[]=rate&fields[]=product_count&fields[]=id&expand[]=products&rate[gt]=80`, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + expect(response.data.tax_rates.some((tr) => tr.rate <= 80)).toEqual(false) + }) + + test("list tax rates w. region query", async () => { + await adminSeeder(dbConnection) + const { regions } = await createTaxRates(dbConnection, 20, 2, 200) + + const api = useApi() + + const response = await api.get( + `/admin/tax-rates?region_id[]=${regions[0].id}®ion_id[]=${regions[1].id}`, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + expect( + response.data.tax_rates.some( + (tr) => tr.region_id !== regions[0].id && tr.region_id !== regions[1].id + ) + ).toEqual(false) + }) + + test("get tax rates", async () => { + await adminSeeder(dbConnection) + const { tax_rates } = await createTaxRates(dbConnection, 20, 2, 200) + + const api = useApi() + + const response = await api.get(`/admin/tax-rates/${tax_rates[0].id}`, { + headers: { + authorization: "Bearer test_token", + }, + }) + + expect(response.status).toEqual(200) + expect(response.data.tax_rate).toMatchSnapshot({ + id: expect.stringMatching(/^txr_*/), + region_id: expect.any(String), + created_at: expect.any(String), + updated_at: expect.any(String), + }) + }) + + test("get tax rates w. fields", async () => { + await adminSeeder(dbConnection) + const { tax_rates } = await createTaxRates(dbConnection, 20, 2, 200) + + const api = useApi() + + const response = await api.get( + `/admin/tax-rates/${tax_rates[0].id}?fields[]=id&fields[]=region_id`, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + expect(response.data.tax_rate).toMatchSnapshot({ + id: expect.stringMatching(/^txr_*/), + region_id: expect.any(String), + }) + }) + + test("assigns tax rate to product type", async () => { + await adminSeeder(dbConnection) + const { tax_rates } = await createTaxRates(dbConnection, 1, 1, 200) + const [rate] = tax_rates + + const product = await simpleProductFactory(dbConnection, { + type: "pants", + }) + + const api = useApi() + + const response = await api.post( + `/admin/tax-rates/${rate.id}/product-types/batch?fields[]=id&fields[]=region_id&fields[]=product_type_count&expand[]=product_types`, + { + product_types: [product.type_id], + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + expect(response.data.tax_rate.product_type_count).toEqual(1) + expect(response.data.tax_rate.product_types[0].id).toEqual(product.type_id) + }) + + test("assigns tax rate to multiple product type", async () => { + await adminSeeder(dbConnection) + const { tax_rates } = await createTaxRates(dbConnection, 1, 1, 200) + const [rate] = tax_rates + + const products = await Promise.all( + [0, 1, 2, 3].map((i) => + simpleProductFactory(dbConnection, { + type: `pants-${i}`, + }) + ) + ) + + const api = useApi() + + const response = await api.post( + `/admin/tax-rates/${rate.id}/product-types/batch?fields[]=id&fields[]=region_id&fields[]=product_type_count&expand[]=product_types`, + { + product_types: products.map((product) => product.type_id), + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + expect(response.data.tax_rate.product_type_count).toEqual(4) + expect(response.data.tax_rate.product_types[0].id).toEqual( + products[0].type_id + ) + expect(response.data.tax_rate.product_types[1].id).toEqual( + products[1].type_id + ) + expect(response.data.tax_rate.product_types[2].id).toEqual( + products[2].type_id + ) + expect(response.data.tax_rate.product_types[3].id).toEqual( + products[3].type_id + ) + }) + + test.only("fails with 404 on unknown rate", async () => { + await adminSeeder(dbConnection) + const { tax_rates } = await createTaxRates(dbConnection, 1, 1, 200) + const [rate] = tax_rates + + await Promise.all( + [0, 1, 2, 3].map(() => simpleProductFactory(dbConnection)) + ) + + const api = useApi() + + const response = await api + .post( + `/admin/tax-rates/${rate.id}/products/batch?fields[]=id&fields[]=product_count&expand[]=products`, + { + products: ["unknown_product_id"], + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + .catch((err) => err.response) + + expect(response.status).toEqual(404) + expect(response.data.message).toEqual( + "Product with id: unknown_product_id was not found" + ) + }) + + test("fails with 404 on unknown prod", async () => { + await adminSeeder(dbConnection) + await createTaxRates(dbConnection, 1, 1, 200) + const products = await Promise.all( + [0, 1, 2, 3].map(() => simpleProductFactory(dbConnection)) + ) + + const api = useApi() + + const response = await api + .post( + `/admin/tax-rates/unknown_rate/products/batch?fields[]=id&fields[]=product_count&expand[]=products`, + { + products: products.map((product) => product.id), + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + .catch((err) => err.response) + + expect(response.status).toEqual(404) + expect(response.data.message).toEqual( + "TaxRate with unknown_rate was not found" + ) + }) + + test("fails to assign rate to shipping option with different reg", async () => { + await adminSeeder(dbConnection) + const { tax_rates, regions } = await createTaxRates(dbConnection, 1, 1, 200) + const [reg] = regions + const [rate] = tax_rates + + const difReg = await simpleRegionFactory(dbConnection) + const option = await simpleShippingOptionFactory(dbConnection, { + name: "Test option", + region_id: difReg, + }) + + const api = useApi() + + const response = await api + .post( + `/admin/tax-rates/${rate.id}/shipping-options/batch?fields[]=id&fields[]=shipping_option_count&expand[]=shipping_options`, + { + shipping_options: [option.id], + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + .catch((err) => err.response) + + expect(response.status).toEqual(400) + expect(response.data.message).toEqual( + `Shipping Option and Tax Rate must belong to the same Region to be associated. Shipping Option with id: ${option.id} belongs to Region with id: ${option.region_id} and Tax Rate with id: ${rate.id} belongs to Region with id: ${rate.region_id}` + ) + }) + + test("assigns tax rate to shipping option", async () => { + await adminSeeder(dbConnection) + const { tax_rates, regions } = await createTaxRates(dbConnection, 1, 1, 200) + const [reg] = regions + const [rate] = tax_rates + + const options = await Promise.all( + [0, 1, 2, 3].map((i) => + simpleShippingOptionFactory(dbConnection, { + name: i, + region_id: reg.id, + }) + ) + ) + + const api = useApi() + + const response = await api.post( + `/admin/tax-rates/${rate.id}/shipping-options/batch?fields[]=id&fields[]=shipping_option_count&expand[]=shipping_options`, + { + shipping_options: options.map((o) => o.id), + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + expect(response.data.tax_rate.shipping_option_count).toEqual(4) + expect(response.data.tax_rate.shipping_options[0].id).toEqual(options[0].id) + expect(response.data.tax_rate.shipping_options[1].id).toEqual(options[1].id) + expect(response.data.tax_rate.shipping_options[2].id).toEqual(options[2].id) + expect(response.data.tax_rate.shipping_options[3].id).toEqual(options[3].id) + }) + + test("assigns tax rate to products", async () => { + await adminSeeder(dbConnection) + const { tax_rates } = await createTaxRates(dbConnection, 1, 1, 200) + const [rate] = tax_rates + + const products = await Promise.all( + [0, 1, 2, 3].map(() => simpleProductFactory(dbConnection)) + ) + + const api = useApi() + + const response = await api.post( + `/admin/tax-rates/${rate.id}/products/batch?fields[]=id&fields[]=product_count&expand[]=products`, + { + products: products.map((product) => product.id), + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + expect(response.data.tax_rate.product_count).toEqual(4) + expect(response.data.tax_rate.products[0].id).toEqual(products[0].id) + expect(response.data.tax_rate.products[1].id).toEqual(products[1].id) + expect(response.data.tax_rate.products[2].id).toEqual(products[2].id) + expect(response.data.tax_rate.products[3].id).toEqual(products[3].id) + }) + + test("creates a tax rate", async () => { + await adminSeeder(dbConnection) + + const api = useApi() + await simpleRegionFactory(dbConnection, { + id: "test-region", + }) + + const response = await api.post( + `/admin/tax-rates`, + { + name: "special", + code: "tricks", + region_id: "test-region", + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + expect(response.data.tax_rate).toMatchSnapshot({ + id: expect.stringMatching(/^txr_*/), + created_at: expect.any(String), + updated_at: expect.any(String), + }) + }) + + test("creates a tax rate and assigns products", async () => { + await adminSeeder(dbConnection) + + const products = await Promise.all( + [0, 1, 2, 3].map(() => simpleProductFactory(dbConnection)) + ) + + await simpleRegionFactory(dbConnection, { + id: "test-region", + }) + + const api = useApi() + const response = await api.post( + `/admin/tax-rates?fields[]=product_count&expand[]=products`, + { + name: "special", + code: "tricks", + region_id: "test-region", + products: products.map((p) => p.id), + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + expect(response.data.tax_rate.product_count).toEqual(4) + }) + + test("updates a tax rate", async () => { + await adminSeeder(dbConnection) + + await simpleRegionFactory(dbConnection, { id: "test-region" }) + + const rate = await simpleTaxRateFactory(dbConnection, { + name: "test", + code: "something", + rate: 10, + region_id: "test-region", + }) + + const api = useApi() + const response = await api.post( + `/admin/tax-rates/${rate.id}`, + { + name: "special", + code: "something new", + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + expect(response.data.tax_rate).toMatchSnapshot({ + id: expect.stringMatching(/^txr_*/), + code: "special", + code: "something new", + created_at: expect.any(String), + updated_at: expect.any(String), + }) + }) + + test("deletes a tax rate", async () => { + await adminSeeder(dbConnection) + + await simpleRegionFactory(dbConnection, { id: "test-region" }) + + const rate = await simpleTaxRateFactory(dbConnection, { + name: "test", + code: "something", + rate: 10, + region_id: "test-region", + }) + + const api = useApi() + const response = await api.delete(`/admin/tax-rates/${rate.id}`, { + headers: { + authorization: "Bearer test_token", + }, + }) + + expect(response.status).toEqual(200) + expect(response.data).toMatchSnapshot({ + id: expect.stringMatching(/^txr_*/), + }) + }) +}) + +const createTaxRates = async (dbConnection, num, numRegions, seed) => { + const regions = [] + for (let i = 0; i < numRegions; i++) { + const reg = await simpleRegionFactory(dbConnection, {}, seed + i) + regions.push(reg) + } + + const tax_rates = [] + for (let x = 0; x < num; x++) { + const { id } = regions[Math.floor(Math.random() * regions.length)] + const rate = await simpleTaxRateFactory( + dbConnection, + { + region_id: id, + }, + seed + x + ) + + tax_rates.push(rate) + } + + return { regions, tax_rates } +} diff --git a/integration-tests/api/__tests__/taxes/automatic-taxes.js b/integration-tests/api/__tests__/taxes/automatic-taxes.js new file mode 100644 index 0000000000..6a1bae01f6 --- /dev/null +++ b/integration-tests/api/__tests__/taxes/automatic-taxes.js @@ -0,0 +1,478 @@ +const path = require("path") + +const setupServer = require("../../../helpers/setup-server") +const { useApi } = require("../../../helpers/use-api") +const { initDb, useDb } = require("../../../helpers/use-db") + +const { + simpleProductTaxRateFactory, + simpleShippingTaxRateFactory, + simpleProductTypeTaxRateFactory, + simpleShippingOptionFactory, + simpleCartFactory, + simpleRegionFactory, + simpleProductFactory, +} = require("../../factories") + +jest.setTimeout(30000) + +describe("Automatic Cart Taxes", () => { + let medusaProcess + let dbConnection + + const doAfterEach = async () => { + const db = useDb() + return await db.teardown() + } + + beforeAll(async () => { + const cwd = path.resolve(path.join(__dirname, "..", "..")) + try { + dbConnection = await initDb({ cwd }) + medusaProcess = await setupServer({ cwd }) + } catch (error) { + console.log(error) + } + }) + + afterAll(async () => { + const db = useDb() + await db.shutdown() + medusaProcess.kill() + }) + + afterEach(async () => { + return await doAfterEach() + }) + + test("correct calculation w. default tax rate", async () => { + await simpleProductFactory( + dbConnection, + { + id: "test-product", + variants: [ + { + id: "test-variant", + }, + ], + }, + 100 + ) + + await simpleCartFactory( + dbConnection, + { + id: "test-cart", + region: { + id: "test-region", + name: "Test region", + tax_rate: 12, + }, + line_items: [ + { + variant_id: "test-variant", + unit_price: 100, + }, + ], + }, + 100 + ) + + const api = useApi() + + const response = await api.get("/store/carts/test-cart") + expect(response.status).toEqual(200) + expect(response.data.cart.tax_total).toEqual(12) + expect(response.data.cart.total).toEqual(112) + }) + + test("correct calculation w. default tax rate w. shipping", async () => { + await simpleProductFactory( + dbConnection, + { + id: "test-product", + variants: [ + { + id: "test-variant", + }, + ], + }, + 100 + ) + + await simpleCartFactory( + dbConnection, + { + id: "test-cart", + region: { + id: "test-region", + name: "Test region", + tax_rate: 12, + }, + shipping_methods: [ + { + shipping_option: { + name: "random", + region_id: "test-region", + }, + price: 100, + }, + ], + line_items: [ + { + variant_id: "test-variant", + unit_price: 100, + }, + ], + }, + 100 + ) + + const api = useApi() + + const response = await api.get("/store/carts/test-cart") + expect(response.status).toEqual(200) + expect(response.data.cart.tax_total).toEqual(24) + expect(response.data.cart.total).toEqual(224) + }) + + test("correct calculation w. same type + prod tax rate", async () => { + const product = await simpleProductFactory( + dbConnection, + { + type: "Pants", + variants: [ + { + id: "test-variant", + }, + ], + }, + 100 + ) + + const region = await simpleRegionFactory(dbConnection, { + name: "Test region", + tax_rate: 12, + }) + + const prodRate = await simpleProductTaxRateFactory(dbConnection, { + product_id: product.id, + rate: { + region_id: region.id, + rate: 10, + }, + }) + + await simpleProductTypeTaxRateFactory(dbConnection, { + product_type_id: product.type_id, + rate: prodRate.rate_id, + }) + + const cart = await simpleCartFactory( + dbConnection, + { + region: region.id, + line_items: [ + { + variant_id: "test-variant", + unit_price: 100, + }, + ], + }, + 100 + ) + + const api = useApi() + + const response = await api.get(`/store/carts/${cart.id}`) + expect(response.status).toEqual(200) + expect(response.data.cart.tax_total).toEqual(10) + expect(response.data.cart.total).toEqual(110) + }) + + test("correct calculation w. type + prod tax rate", async () => { + const product = await simpleProductFactory( + dbConnection, + { + type: "Pants", + variants: [ + { + id: "test-variant", + }, + ], + }, + 100 + ) + + const region = await simpleRegionFactory(dbConnection, { + name: "Test region", + tax_rate: 12, + }) + + await simpleProductTaxRateFactory(dbConnection, { + product_id: product.id, + rate: { + region_id: region.id, + rate: 10, + }, + }) + + await simpleProductTypeTaxRateFactory(dbConnection, { + product_type_id: product.type_id, + rate: { + region_id: region.id, + rate: 25, + }, + }) + + const cart = await simpleCartFactory( + dbConnection, + { + region: region.id, + line_items: [ + { + variant_id: "test-variant", + unit_price: 100, + }, + ], + }, + 100 + ) + + const api = useApi() + + const response = await api.get(`/store/carts/${cart.id}`) + expect(response.status).toEqual(200) + expect(response.data.cart.tax_total).toEqual(35) + expect(response.data.cart.total).toEqual(135) + }) + + test("correct calculation w. tax rate override type", async () => { + const product = await simpleProductFactory( + dbConnection, + { + type: "Pants", + variants: [ + { + id: "test-variant", + }, + ], + }, + 100 + ) + + const region = await simpleRegionFactory(dbConnection, { + name: "Test region", + tax_rate: 12, + }) + + await simpleProductTypeTaxRateFactory(dbConnection, { + product_type_id: product.type_id, + rate: { + region_id: region.id, + rate: 25, + }, + }) + + const cart = await simpleCartFactory( + dbConnection, + { + region: region.id, + line_items: [ + { + variant_id: "test-variant", + unit_price: 100, + }, + ], + }, + 100 + ) + + const api = useApi() + + const response = await api.get(`/store/carts/${cart.id}`) + expect(response.status).toEqual(200) + expect(response.data.cart.tax_total).toEqual(25) + expect(response.data.cart.total).toEqual(125) + }) + + test("correct calculation w. tax rate override", async () => { + const product = await simpleProductFactory( + dbConnection, + { + variants: [ + { + id: "test-variant", + }, + ], + }, + 100 + ) + + const region = await simpleRegionFactory(dbConnection, { + name: "Test region", + tax_rate: 12, + }) + + await simpleProductTaxRateFactory(dbConnection, { + product_id: product.id, + rate: { + region_id: region.id, + rate: 25, + }, + }) + + const cart = await simpleCartFactory( + dbConnection, + { + region: region.id, + line_items: [ + { + variant_id: "test-variant", + unit_price: 100, + }, + ], + }, + 100 + ) + + const api = useApi() + + const response = await api.get(`/store/carts/${cart.id}`) + expect(response.status).toEqual(200) + expect(response.data.cart.tax_total).toEqual(25) + expect(response.data.cart.total).toEqual(125) + }) + + test("correct calculation w. tax rate override w. shipping", async () => { + await simpleProductFactory( + dbConnection, + { + variants: [ + { + id: "test-variant", + }, + ], + }, + 100 + ) + + const region = await simpleRegionFactory(dbConnection, { + name: "Test region", + tax_rate: 12, + }) + + const option = await simpleShippingOptionFactory(dbConnection, { + name: "random", + region_id: region.id, + }) + + await simpleShippingTaxRateFactory(dbConnection, { + shipping_option_id: option.id, + rate: { + region_id: region.id, + rate: 25, + }, + }) + + const cart = await simpleCartFactory( + dbConnection, + { + region: region.id, + line_items: [ + { + variant_id: "test-variant", + unit_price: 100, + }, + ], + shipping_methods: [ + { + shipping_option: option.id, + price: 100, + }, + ], + }, + 100 + ) + + const api = useApi() + + const response = await api.get(`/store/carts/${cart.id}`) + expect(response.status).toEqual(200) + expect(response.data.cart.tax_total).toEqual(37) + expect(response.data.cart.total).toEqual(237) + }) + + test("correct calculation w. multiple tax rate overrides", async () => { + const product1 = await simpleProductFactory( + dbConnection, + { + variants: [ + { + id: "test-variant", + }, + ], + }, + 100 + ) + + const product2 = await simpleProductFactory( + dbConnection, + { + variants: [ + { + id: "test-variant-2", + }, + ], + }, + 100 + ) + + const region = await simpleRegionFactory(dbConnection, { + name: "Test region", + tax_rate: 12, + }) + + await simpleProductTaxRateFactory(dbConnection, { + product_id: product1.id, + rate: { + region_id: region.id, + rate: 25, + }, + }) + + await simpleProductTaxRateFactory(dbConnection, { + product_id: product2.id, + rate: { + region_id: region.id, + rate: 20, + }, + }) + + const cart = await simpleCartFactory( + dbConnection, + { + region: region.id, + line_items: [ + { + variant_id: "test-variant", + unit_price: 100, + }, + { + variant_id: "test-variant-2", + unit_price: 50, + }, + ], + }, + 100 + ) + + const api = useApi() + + const response = await api.get(`/store/carts/${cart.id}`) + + expect(response.status).toEqual(200) + expect(response.data.cart.tax_total).toEqual(35) + expect(response.data.cart.total).toEqual(185) + }) +}) diff --git a/integration-tests/api/__tests__/taxes/manual-taxes.js b/integration-tests/api/__tests__/taxes/manual-taxes.js new file mode 100644 index 0000000000..79c53033a5 --- /dev/null +++ b/integration-tests/api/__tests__/taxes/manual-taxes.js @@ -0,0 +1,204 @@ +const path = require("path") + +const setupServer = require("../../../helpers/setup-server") +const { useApi } = require("../../../helpers/use-api") +const { initDb, useDb } = require("../../../helpers/use-db") + +const { + simpleProductTaxRateFactory, + simpleShippingTaxRateFactory, + simpleShippingOptionFactory, + simpleCartFactory, + simpleRegionFactory, + simpleProductFactory, +} = require("../../factories") + +jest.setTimeout(30000) + +describe("Manual Cart Taxes", () => { + let medusaProcess + let dbConnection + + const doAfterEach = async () => { + const db = useDb() + return await db.teardown() + } + + beforeAll(async () => { + const cwd = path.resolve(path.join(__dirname, "..", "..")) + try { + dbConnection = await initDb({ cwd }) + medusaProcess = await setupServer({ cwd }) + } catch (error) { + console.log(error) + } + }) + + afterAll(async () => { + const db = useDb() + await db.shutdown() + medusaProcess.kill() + }) + + afterEach(async () => { + return await doAfterEach() + }) + + test("manual taxes; default tax rate", async () => { + await simpleProductFactory( + dbConnection, + { + id: "test-product", + variants: [ + { + id: "test-variant", + }, + ], + }, + 100 + ) + + await simpleCartFactory( + dbConnection, + { + id: "test-cart", + region: { + id: "test-region", + name: "Test region", + tax_rate: 12, + automatic_taxes: false, + }, + line_items: [ + { + variant_id: "test-variant", + unit_price: 100, + }, + ], + }, + 100 + ) + + const api = useApi() + + const response = await api.get("/store/carts/test-cart") + expect(response.status).toEqual(200) + expect(response.data.cart.tax_total).toEqual(null) + expect(response.data.cart.total).toEqual(100) + }) + + test("manual taxes; always forces taxes for payment sessions", async () => { + await simpleProductFactory( + dbConnection, + { + id: "test-product", + variants: [ + { + id: "test-variant", + }, + ], + }, + 100 + ) + + await simpleCartFactory( + dbConnection, + { + id: "test-cart", + region: { + id: "test-region", + name: "Test region", + tax_rate: 12, + automatic_taxes: false, + }, + line_items: [ + { + variant_id: "test-variant", + unit_price: 100, + }, + ], + }, + 100 + ) + + const api = useApi() + + const response = await api.post("/store/carts/test-cart/payment-sessions") + expect(response.status).toEqual(200) + const [paySession] = response.data.cart.payment_sessions + expect(paySession.data.tax_total).toEqual(12) + expect(paySession.data.total).toEqual(112) + }) + + test("manual tax calculation w. multiple tax rate overrides", async () => { + const product1 = await simpleProductFactory( + dbConnection, + { + variants: [ + { + id: "test-variant", + }, + ], + }, + 100 + ) + + const product2 = await simpleProductFactory( + dbConnection, + { + variants: [ + { + id: "test-variant-2", + }, + ], + }, + 100 + ) + + const region = await simpleRegionFactory(dbConnection, { + name: "Test region", + tax_rate: 12, + }) + + await simpleProductTaxRateFactory(dbConnection, { + product_id: product1.id, + rate: { + region_id: region.id, + rate: 25, + }, + }) + + await simpleProductTaxRateFactory(dbConnection, { + product_id: product2.id, + rate: { + region_id: region.id, + rate: 20, + }, + }) + + const cart = await simpleCartFactory( + dbConnection, + { + region: region.id, + line_items: [ + { + variant_id: "test-variant", + unit_price: 100, + }, + { + variant_id: "test-variant-2", + unit_price: 50, + }, + ], + }, + 100 + ) + + const api = useApi() + + const response = await api.post(`/store/carts/${cart.id}/taxes`) + + expect(response.status).toEqual(200) + expect(response.data.cart.tax_total).toEqual(35) + expect(response.data.cart.total).toEqual(185) + }) +}) diff --git a/integration-tests/api/__tests__/taxes/orders.js b/integration-tests/api/__tests__/taxes/orders.js new file mode 100644 index 0000000000..9acab356bd --- /dev/null +++ b/integration-tests/api/__tests__/taxes/orders.js @@ -0,0 +1,290 @@ +const path = require("path") + +const setupServer = require("../../../helpers/setup-server") +const { useApi } = require("../../../helpers/use-api") +const { initDb, useDb } = require("../../../helpers/use-db") + +const { + simpleOrderFactory, + simpleRegionFactory, + simpleCartFactory, + simpleProductFactory, + simpleProductTaxRateFactory, +} = require("../../factories") + +jest.setTimeout(30000) + +describe("Order Taxes", () => { + let medusaProcess + let dbConnection + + const doAfterEach = async () => { + const db = useDb() + return await db.teardown() + } + + beforeAll(async () => { + const cwd = path.resolve(path.join(__dirname, "..", "..")) + try { + dbConnection = await initDb({ cwd }) + medusaProcess = await setupServer({ cwd }) + } catch (error) { + console.log(error) + } + }) + + afterAll(async () => { + const db = useDb() + await db.shutdown() + medusaProcess.kill() + }) + + afterEach(async () => { + return await doAfterEach() + }) + + test("can calculate taxes for legacy tax system", async () => { + await simpleProductFactory( + dbConnection, + { + id: "test-product", + variants: [ + { + id: "test-variant", + }, + ], + }, + 100 + ) + + const order = await simpleOrderFactory( + dbConnection, + { + email: "test@testson.com", + region: { + id: "test-region", + name: "Test region", + tax_rate: 12.5, + }, + line_items: [ + { + variant_id: "test-variant", + unit_price: 1000, + }, + ], + }, + 100 + ) + + const api = useApi() + + const response = await api.get(`/store/orders/${order.id}`) + expect(response.status).toEqual(200) + expect(response.data.order.tax_total).toEqual(125) + expect(response.data.order.total).toEqual(1125) + }) + + test("calculates taxes correctly", async () => { + await simpleProductFactory( + dbConnection, + { + id: "test-product", + variants: [ + { + id: "test-variant", + }, + ], + }, + 100 + ) + + const order = await simpleOrderFactory( + dbConnection, + { + email: "test@testson.com", + tax_rate: null, + region: { + id: "test-region", + name: "Test region", + tax_rate: null, + }, + line_items: [ + { + variant_id: "test-variant", + unit_price: 1000, + tax_lines: [ + { + rate: 20, + name: "default", + code: "default", + }, + ], + }, + ], + }, + 100 + ) + + const api = useApi() + + const response = await api.get(`/store/orders/${order.id}`) + expect(response.status).toEqual(200) + expect(response.data.order.tax_total).toEqual(200) + expect(response.data.order.total).toEqual(1200) + }) + + test("calculates taxes correctly w. shipping method", async () => { + await simpleProductFactory( + dbConnection, + { + id: "test-product", + variants: [ + { + id: "test-variant", + }, + ], + }, + 100 + ) + + const order = await simpleOrderFactory( + dbConnection, + { + email: "test@testson.com", + tax_rate: null, + region: { + id: "test-region", + name: "Test region", + tax_rate: null, + }, + shipping_methods: [ + { + price: 1000, + shipping_option: { + region_id: "test-region", + }, + tax_lines: [ + { + rate: 10, + name: "default", + code: "default", + }, + ], + }, + ], + line_items: [ + { + variant_id: "test-variant", + unit_price: 1000, + tax_lines: [ + { + rate: 20, + name: "default", + code: "default", + }, + ], + }, + ], + }, + 100 + ) + + const api = useApi() + + const response = await api.get(`/store/orders/${order.id}`) + expect(response.status).toEqual(200) + expect(response.data.order.tax_total).toEqual(300) + expect(response.data.order.total).toEqual(2300) + }) + + test("completing cart creates tax lines", async () => { + const product1 = await simpleProductFactory( + dbConnection, + { + variants: [ + { + id: "test-variant", + }, + ], + }, + 100 + ) + + const product2 = await simpleProductFactory( + dbConnection, + { + variants: [ + { + id: "test-variant-2", + }, + ], + }, + 100 + ) + + const region = await simpleRegionFactory(dbConnection, { + name: "Test region", + tax_rate: 12, + }) + + await simpleProductTaxRateFactory(dbConnection, { + product_id: product1.id, + rate: { + region_id: region.id, + rate: 25, + }, + }) + + await simpleProductTaxRateFactory(dbConnection, { + product_id: product2.id, + rate: { + region_id: region.id, + rate: 20, + }, + }) + + const cart = await simpleCartFactory( + dbConnection, + { + region: region.id, + email: "test@testson.com", + line_items: [ + { + variant_id: "test-variant", + unit_price: 100, + }, + { + variant_id: "test-variant-2", + unit_price: 50, + }, + ], + }, + 100 + ) + + const api = useApi() + + await api.post(`/store/carts/${cart.id}`, { + email: "test@testson.com", + }) + await api.post(`/store/carts/${cart.id}/payment-sessions`) + const response = await api.post(`/store/carts/${cart.id}/complete`) + + expect(response.status).toEqual(200) + + expect(response.data.type).toEqual("order") + expect(response.data.data.tax_total).toEqual(35) + expect(response.data.data.total).toEqual(185) + + expect(response.data.data.items[0].tax_lines).toEqual([ + expect.objectContaining({ + rate: 25, + }), + ]) + expect(response.data.data.items[1].tax_lines).toEqual([ + expect.objectContaining({ + rate: 20, + }), + ]) + }) +}) diff --git a/integration-tests/api/factories/index.ts b/integration-tests/api/factories/index.ts new file mode 100644 index 0000000000..02b884d37e --- /dev/null +++ b/integration-tests/api/factories/index.ts @@ -0,0 +1,13 @@ +export * from "./simple-payment-factory" +export * from "./simple-order-factory" +export * from "./simple-cart-factory" +export * from "./simple-region-factory" +export * from "./simple-line-item-factory" +export * from "./simple-product-factory" +export * from "./simple-product-variant-factory" +export * from "./simple-product-tax-rate-factory" +export * from "./simple-shipping-tax-rate-factory" +export * from "./simple-tax-rate-factory" +export * from "./simple-shipping-option-factory" +export * from "./simple-shipping-method-factory" +export * from "./simple-product-type-tax-rate-factory" diff --git a/integration-tests/api/factories/simple-address-factory.ts b/integration-tests/api/factories/simple-address-factory.ts new file mode 100644 index 0000000000..cb40d162d8 --- /dev/null +++ b/integration-tests/api/factories/simple-address-factory.ts @@ -0,0 +1,34 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { Address } from "@medusajs/medusa" + +export type AddressFactoryData = { + first_name?: string + last_name?: string + country_code?: string + address_1?: string + postal_code?: string +} + +export const simpleAddressFactory = async ( + connection: Connection, + data: AddressFactoryData = {}, + seed?: number +): Promise
=> { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + const address = manager.create(Address, { + id: `simple-id-${Math.random() * 1000}`, + first_name: data.first_name || faker.name.firstName(), + last_name: data.last_name || faker.name.lastName(), + country_code: data.country_code || "us", + address_1: data.address_1 || faker.address.streetAddress(), + postal_code: data.postal_code || faker.address.zipCode(), + }) + + return await manager.save(address) +} diff --git a/integration-tests/api/factories/simple-cart-factory.ts b/integration-tests/api/factories/simple-cart-factory.ts new file mode 100644 index 0000000000..33a10cff75 --- /dev/null +++ b/integration-tests/api/factories/simple-cart-factory.ts @@ -0,0 +1,70 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { Cart } from "@medusajs/medusa" + +import { RegionFactoryData, simpleRegionFactory } from "./simple-region-factory" +import { + LineItemFactoryData, + simpleLineItemFactory, +} from "./simple-line-item-factory" +import { + AddressFactoryData, + simpleAddressFactory, +} from "./simple-address-factory" +import { + ShippingMethodFactoryData, + simpleShippingMethodFactory, +} from "./simple-shipping-method-factory" + +export type CartFactoryData = { + id?: string + region?: RegionFactoryData | string + email?: string | null + line_items?: LineItemFactoryData[] + shipping_address?: AddressFactoryData + shipping_methods?: ShippingMethodFactoryData[] +} + +export const simpleCartFactory = async ( + connection: Connection, + data: CartFactoryData = {}, + seed: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + let regionId: string + if (typeof data.region === "string") { + regionId = data.region + } else { + const region = await simpleRegionFactory(connection, data.region) + regionId = region.id + } + const address = await simpleAddressFactory(connection, data.shipping_address) + + const id = data.id || `simple-cart-${Math.random() * 1000}` + const toSave = manager.create(Cart, { + id, + email: + typeof data.email !== "undefined" ? data.email : faker.internet.email(), + region_id: regionId, + shipping_address_id: address.id, + }) + + const cart = await manager.save(toSave) + + const shippingMethods = data.shipping_methods || [] + for (const sm of shippingMethods) { + await simpleShippingMethodFactory(connection, { ...sm, cart_id: id }) + } + + const items = data.line_items + for (const item of items) { + await simpleLineItemFactory(connection, { ...item, cart_id: id }) + } + + return cart +} diff --git a/integration-tests/api/factories/simple-discount-factory.ts b/integration-tests/api/factories/simple-discount-factory.ts new file mode 100644 index 0000000000..8fbb13cd28 --- /dev/null +++ b/integration-tests/api/factories/simple-discount-factory.ts @@ -0,0 +1,55 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { + Discount, + DiscountRule, + DiscountRuleType, + AllocationType, +} from "@medusajs/medusa" + +export type DiscountRuleFactoryData = { + type?: DiscountRuleType + value?: number + allocation?: AllocationType +} + +export type DiscountFactoryData = { + id?: string + code?: string + is_dynamic?: boolean + rule?: DiscountRuleFactoryData + regions?: string[] +} + +export const simpleDiscountFactory = async ( + connection: Connection, + data: DiscountFactoryData = {}, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + const ruleData = data.rule ?? {} + const ruleToSave = manager.create(DiscountRule, { + type: ruleData.type ?? DiscountRuleType.PERCENTAGE, + value: ruleData.value ?? 10, + allocation: ruleData.allocation ?? AllocationType.TOTAL, + }) + + const dRule = await manager.save(ruleToSave) + + const toSave = manager.create(Discount, { + id: data.id, + is_dynamic: data.is_dynamic ?? false, + is_disabled: false, + rule_id: dRule.id, + code: data.code ?? "TESTCODE", + regions: data.regions?.map((r) => ({ id: r })) || [], + }) + + const discount = await manager.save(toSave) + return discount +} diff --git a/integration-tests/api/factories/simple-line-item-factory.ts b/integration-tests/api/factories/simple-line-item-factory.ts new file mode 100644 index 0000000000..84995c79f3 --- /dev/null +++ b/integration-tests/api/factories/simple-line-item-factory.ts @@ -0,0 +1,84 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { LineItem, LineItemTaxLine } from "@medusajs/medusa" + +type TaxLineFactoryData = { + rate: number + code: string + name: string +} + +export type LineItemFactoryData = { + id?: string + cart_id?: string + order_id?: string + variant_id: string | null + title?: string + description?: string + thumbnail?: string + should_merge?: boolean + allow_discounts?: boolean + unit_price?: number + quantity?: number + fulfilled_quantity?: boolean + shipped_quantity?: boolean + returned_quantity?: boolean + tax_lines?: TaxLineFactoryData[] +} + +export const simpleLineItemFactory = async ( + connection: Connection, + data: LineItemFactoryData, + seed?: number +): Promise => { + if ( + typeof data.cart_id === "undefined" && + typeof data.order_id === "undefined" + ) { + throw Error() + } + + if (typeof seed !== "undefined") { + faker.seed(seed) + Math + } + + const manager = connection.manager + + const id = data.id || `simple-line-${Math.random() * 1000}` + const toSave = manager.create(LineItem, { + id, + cart_id: data.cart_id, + order_id: data.order_id, + title: data.title || faker.commerce.productName(), + description: data.description || "", + thumbnail: data.thumbnail || "", + should_merge: + typeof data.should_merge !== "undefined" ? data.should_merge : true, + allow_discounts: + typeof data.allow_discounts !== "undefined" ? data.allow_discounts : true, + unit_price: typeof data.unit_price !== "undefined" ? data.unit_price : 100, + variant_id: data.variant_id, + quantity: data.quantity || 1, + fulfilled_quantity: data.fulfilled_quantity || null, + shipped_quantity: data.shipped_quantity || null, + returned_quantity: data.returned_quantity || null, + }) + + const line = await manager.save(toSave) + + if (typeof data.tax_lines !== "undefined") { + const taxLinesToSave = data.tax_lines.map((tl) => + manager.create(LineItemTaxLine, { + item_id: id, + rate: tl.rate, + code: tl.code, + name: tl.name, + }) + ) + + await manager.save(taxLinesToSave) + } + + return line +} diff --git a/integration-tests/api/factories/simple-order-factory.ts b/integration-tests/api/factories/simple-order-factory.ts new file mode 100644 index 0000000000..4153aa0fe2 --- /dev/null +++ b/integration-tests/api/factories/simple-order-factory.ts @@ -0,0 +1,110 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { + Customer, + Order, + PaymentStatus, + FulfillmentStatus, +} from "@medusajs/medusa" + +import { + DiscountFactoryData, + simpleDiscountFactory, +} from "./simple-discount-factory" +import { RegionFactoryData, simpleRegionFactory } from "./simple-region-factory" +import { + LineItemFactoryData, + simpleLineItemFactory, +} from "./simple-line-item-factory" +import { + AddressFactoryData, + simpleAddressFactory, +} from "./simple-address-factory" +import { + ShippingMethodFactoryData, + simpleShippingMethodFactory, +} from "./simple-shipping-method-factory" + +export type OrderFactoryData = { + id?: string + payment_status?: PaymentStatus + fulfillment_status?: FulfillmentStatus + region?: RegionFactoryData | string + email?: string | null + currency_code?: string + tax_rate?: number | null + line_items?: LineItemFactoryData[] + discounts?: DiscountFactoryData[] + shipping_address?: AddressFactoryData + shipping_methods?: ShippingMethodFactoryData[] +} + +export const simpleOrderFactory = async ( + connection: Connection, + data: OrderFactoryData = {}, + seed: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + let currencyCode: string + let regionId: string + let taxRate: number + if (typeof data.region === "string") { + currencyCode = data.currency_code + regionId = data.region + taxRate = data.tax_rate + } else { + const region = await simpleRegionFactory(connection, data.region) + taxRate = + typeof data.tax_rate !== "undefined" ? data.tax_rate : region.tax_rate + currencyCode = region.currency_code + regionId = region.id + } + const address = await simpleAddressFactory(connection, data.shipping_address) + + const customerToSave = manager.create(Customer, { + email: + typeof data.email !== "undefined" ? data.email : faker.internet.email(), + }) + const customer = await manager.save(customerToSave) + + let discounts = [] + if (typeof data.discounts !== "undefined") { + discounts = await Promise.all( + data.discounts.map((d) => simpleDiscountFactory(connection, d, seed)) + ) + } + + const id = data.id || `simple-order-${Math.random() * 1000}` + const toSave = manager.create(Order, { + id, + discounts, + payment_status: data.payment_status ?? PaymentStatus.AWAITING, + fulfillment_status: + data.fulfillment_status ?? FulfillmentStatus.NOT_FULFILLED, + customer_id: customer.id, + email: customer.email, + region_id: regionId, + currency_code: currencyCode, + tax_rate: taxRate, + shipping_address_id: address.id, + }) + + const order = await manager.save(toSave) + + const shippingMethods = data.shipping_methods || [] + for (const sm of shippingMethods) { + await simpleShippingMethodFactory(connection, { ...sm, order_id: order.id }) + } + + const items = data.line_items + for (const item of items) { + await simpleLineItemFactory(connection, { ...item, order_id: id }) + } + + return order +} diff --git a/integration-tests/api/factories/simple-payment-factory.ts b/integration-tests/api/factories/simple-payment-factory.ts new file mode 100644 index 0000000000..2c56236438 --- /dev/null +++ b/integration-tests/api/factories/simple-payment-factory.ts @@ -0,0 +1,43 @@ +import { Connection } from "typeorm" +import { Payment } from "@medusajs/medusa" + +export type PaymentFactoryData = { + provider_id?: string + order?: string + cart?: string + data?: any + amount?: number + currency_code?: string + captured?: Date | boolean +} + +export const simplePaymentFactory = async ( + connection: Connection, + data: PaymentFactoryData, + _?: number +): Promise => { + const manager = connection.manager + + let captured_at = data.captured + if (typeof captured_at === "boolean") { + if (captured_at) { + captured_at = new Date() + } else { + captured_at = null + } + } else if (typeof captured_at === "undefined") { + captured_at = null + } + + const address = manager.create(Payment, { + provider_id: data.provider_id ?? "test-pay", + order_id: data.order, + cart_id: data.cart, + data: data.data ?? {}, + amount: data.amount ?? 1000, + currency_code: data.currency_code ?? "usd", + captured_at, + }) + + return await manager.save(address) +} diff --git a/integration-tests/api/factories/simple-product-factory.ts b/integration-tests/api/factories/simple-product-factory.ts new file mode 100644 index 0000000000..24746c0f84 --- /dev/null +++ b/integration-tests/api/factories/simple-product-factory.ts @@ -0,0 +1,99 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { + ShippingProfileType, + ShippingProfile, + Product, + ProductType, + ProductOption, +} from "@medusajs/medusa" + +import { + simpleProductVariantFactory, + ProductVariantFactoryData, +} from "./simple-product-variant-factory" + +export type ProductFactoryData = { + id?: string + is_giftcard?: boolean + title?: string + type?: string + options?: { id: string; title: string }[] + variants?: ProductVariantFactoryData[] +} + +export const simpleProductFactory = async ( + connection: Connection, + data: ProductFactoryData = {}, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + const defaultProfile = await manager.findOne(ShippingProfile, { + type: ShippingProfileType.DEFAULT, + }) + + const gcProfile = await manager.findOne(ShippingProfile, { + type: ShippingProfileType.GIFT_CARD, + }) + + let typeId: string + if (typeof data.type !== "undefined") { + const toSave = manager.create(ProductType, { + value: data.type, + }) + const res = await manager.save(toSave) + typeId = res.id + } + + const prodId = data.id || `simple-product-${Math.random() * 1000}` + const toSave = manager.create(Product, { + id: prodId, + type_id: typeId, + title: data.title || faker.commerce.productName(), + is_giftcard: data.is_giftcard || false, + discountable: !data.is_giftcard, + profile_id: data.is_giftcard ? gcProfile.id : defaultProfile.id, + }) + + const product = await manager.save(toSave) + + const optionId = `${prodId}-option` + const options = data.options || [{ id: optionId, title: "Size" }] + for (const o of options) { + await manager.insert(ProductOption, { + id: o.id, + title: o.title, + product_id: prodId, + }) + } + + const variants = data.variants || [ + { + id: `simple-test-variant-${Math.random() * 1000}`, + title: "Test", + product_id: prodId, + prices: [{ currency: "usd", amount: 100 }], + options: [{ option_id: optionId, value: "Large" }], + }, + ] + + for (const pv of variants) { + const factoryData = { + ...pv, + product_id: prodId, + } + if (typeof pv.options === "undefined") { + factoryData.options = [ + { option_id: optionId, value: faker.commerce.productAdjective() }, + ] + } + await simpleProductVariantFactory(connection, factoryData) + } + + return product +} diff --git a/integration-tests/api/factories/simple-product-tax-rate-factory.ts b/integration-tests/api/factories/simple-product-tax-rate-factory.ts new file mode 100644 index 0000000000..4b731c51b3 --- /dev/null +++ b/integration-tests/api/factories/simple-product-tax-rate-factory.ts @@ -0,0 +1,48 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { ProductTaxRate, TaxRate } from "@medusajs/medusa" + +type RateFactoryData = { + region_id: string + rate?: number | null + code?: string + name?: string +} + +export type ProductTaxRateFactoryData = { + product_id: string + rate: RateFactoryData | string +} + +export const simpleProductTaxRateFactory = async ( + connection: Connection, + data: ProductTaxRateFactoryData, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + let rateId: string + if (typeof data.rate === "string") { + rateId = data.rate + } else { + const newRate = manager.create(TaxRate, { + region_id: data.rate.region_id, + rate: data.rate.rate, + code: data.rate.code || "sales_tax", + name: data.rate.name || "Sales Tax", + }) + const rate = await manager.save(newRate) + rateId = rate.id + } + + const toSave = manager.create(ProductTaxRate, { + product_id: data.product_id, + rate_id: rateId, + }) + + return await manager.save(toSave) +} diff --git a/integration-tests/api/factories/simple-product-type-tax-rate-factory.ts b/integration-tests/api/factories/simple-product-type-tax-rate-factory.ts new file mode 100644 index 0000000000..47402a6cbf --- /dev/null +++ b/integration-tests/api/factories/simple-product-type-tax-rate-factory.ts @@ -0,0 +1,48 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { ProductTypeTaxRate, TaxRate } from "@medusajs/medusa" + +type RateFactoryData = { + region_id: string + rate?: number | null + code?: string + name?: string +} + +export type ProductTypeTaxRateFactoryData = { + product_type_id: string + rate: RateFactoryData | string +} + +export const simpleProductTypeTaxRateFactory = async ( + connection: Connection, + data: ProductTypeTaxRateFactoryData, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + let rateId: string + if (typeof data.rate === "string") { + rateId = data.rate + } else { + const newRate = manager.create(TaxRate, { + region_id: data.rate.region_id, + rate: data.rate.rate, + code: data.rate.code || "sales_tax", + name: data.rate.name || "Sales Tax", + }) + const rate = await manager.save(newRate) + rateId = rate.id + } + + const toSave = manager.create(ProductTypeTaxRate, { + product_type_id: data.product_type_id, + rate_id: rateId, + }) + + return await manager.save(toSave) +} diff --git a/integration-tests/api/factories/simple-product-variant-factory.ts b/integration-tests/api/factories/simple-product-variant-factory.ts new file mode 100644 index 0000000000..8d6f6f9cc9 --- /dev/null +++ b/integration-tests/api/factories/simple-product-variant-factory.ts @@ -0,0 +1,64 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { + ProductOptionValue, + ProductVariant, + MoneyAmount, +} from "@medusajs/medusa" + +export type ProductVariantFactoryData = { + product_id: string + id?: string + is_giftcard?: boolean + inventory_quantity?: number + title?: string + options?: { option_id: string; value: string }[] + prices?: { currency: string; amount: number }[] +} + +export const simpleProductVariantFactory = async ( + connection: Connection, + data: ProductVariantFactoryData, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + const id = data.id || `simple-variant-${Math.random() * 1000}` + const toSave = manager.create(ProductVariant, { + id, + product_id: data.product_id, + inventory_quantity: + typeof data.inventory_quantity !== "undefined" + ? data.inventory_quantity + : 10, + title: data.title || faker.commerce.productName(), + }) + + const variant = await manager.save(toSave) + + const options = data.options || [{ option_id: "test-option", value: "Large" }] + for (const o of options) { + await manager.insert(ProductOptionValue, { + id: `${o.value}-${o.option_id}`, + value: o.value, + variant_id: id, + option_id: o.option_id, + }) + } + + const prices = data.prices || [{ currency: "usd", amount: 100 }] + for (const p of prices) { + await manager.insert(MoneyAmount, { + id: `${p.currency}-${p.amount}-${Math.random()}`, + variant_id: id, + currency_code: p.currency, + amount: p.amount, + }) + } + + return variant +} diff --git a/integration-tests/api/factories/simple-region-factory.ts b/integration-tests/api/factories/simple-region-factory.ts new file mode 100644 index 0000000000..0cd08ea702 --- /dev/null +++ b/integration-tests/api/factories/simple-region-factory.ts @@ -0,0 +1,47 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { Region } from "@medusajs/medusa" + +export type RegionFactoryData = { + id?: string + name?: string + currency_code?: string + tax_rate?: number + countries?: string[] + automatic_taxes?: boolean +} + +export const simpleRegionFactory = async ( + connection: Connection, + data: RegionFactoryData = {}, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + const regionId = data.id || `simple-region-${Math.random() * 1000}` + const r = manager.create(Region, { + id: regionId, + name: data.name || "Test Region", + currency_code: data.currency_code || "usd", + tax_rate: data.tax_rate || 0, + payment_providers: [{ id: "test-pay" }], + automatic_taxes: + typeof data.automatic_taxes !== "undefined" ? data.automatic_taxes : true, + }) + + const region = await manager.save(r) + + const countries = data.countries || ["us"] + + for (const cc of countries) { + await manager.query( + `UPDATE "country" SET region_id='${regionId}' WHERE iso_2 = '${cc}'` + ) + } + + return region +} diff --git a/integration-tests/api/factories/simple-shipping-method-factory.ts b/integration-tests/api/factories/simple-shipping-method-factory.ts new file mode 100644 index 0000000000..3fde22e63d --- /dev/null +++ b/integration-tests/api/factories/simple-shipping-method-factory.ts @@ -0,0 +1,68 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { ShippingMethodTaxLine, ShippingMethod } from "@medusajs/medusa" + +import { + ShippingOptionFactoryData, + simpleShippingOptionFactory, +} from "./simple-shipping-option-factory" + +export type ShippingMethodFactoryData = { + id?: string + cart_id?: string + order_id?: string + data?: object + price?: number + shipping_option: string | ShippingOptionFactoryData + tax_lines?: ShippingMethodTaxLine[] +} + +export const simpleShippingMethodFactory = async ( + connection: Connection, + data: ShippingMethodFactoryData, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + let shippingOptionId: string + if (typeof data.shipping_option === "string") { + shippingOptionId = data.shipping_option + } else { + const option = await simpleShippingOptionFactory( + connection, + data.shipping_option + ) + shippingOptionId = option.id + } + + const id = data.id || `simple-sm-${Math.random() * 1000}` + const toSave = manager.create(ShippingMethod, { + id, + cart_id: data.cart_id, + order_id: data.order_id, + shipping_option_id: shippingOptionId, + data: data.data || {}, + price: typeof data.price !== "undefined" ? data.price : 500, + }) + + const shippingMethod = await manager.save(toSave) + + if (typeof data.tax_lines !== "undefined") { + const taxLinesToSave = data.tax_lines.map((tl) => + manager.create(ShippingMethodTaxLine, { + shipping_method_id: shippingMethod.id, + rate: tl.rate, + code: tl.code || "default", + name: tl.name || "default", + }) + ) + + await manager.save(taxLinesToSave) + } + + return shippingMethod +} diff --git a/integration-tests/api/factories/simple-shipping-option-factory.ts b/integration-tests/api/factories/simple-shipping-option-factory.ts new file mode 100644 index 0000000000..4ceed9dd97 --- /dev/null +++ b/integration-tests/api/factories/simple-shipping-option-factory.ts @@ -0,0 +1,49 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { + ShippingOptionPriceType, + ShippingProfile, + ShippingOption, + ShippingProfileType, +} from "@medusajs/medusa" + +export type ShippingOptionFactoryData = { + name?: string + region_id: string + is_return?: boolean + is_giftcard?: boolean + price?: number +} + +export const simpleShippingOptionFactory = async ( + connection: Connection, + data: ShippingOptionFactoryData, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + const defaultProfile = await manager.findOne(ShippingProfile, { + type: ShippingProfileType.DEFAULT, + }) + + const gcProfile = await manager.findOne(ShippingProfile, { + type: ShippingProfileType.GIFT_CARD, + }) + + const created = manager.create(ShippingOption, { + id: `simple-so-${Math.random() * 1000}`, + name: data.name || "Test Method", + is_return: data.is_return ?? false, + region_id: data.region_id, + provider_id: "test-ful", + profile_id: data.is_giftcard ? gcProfile.id : defaultProfile.id, + price_type: ShippingOptionPriceType.FLAT_RATE, + data: {}, + amount: typeof data.price !== "undefined" ? data.price : 500, + }) + const option = await manager.save(created) + return option +} diff --git a/integration-tests/api/factories/simple-shipping-tax-rate-factory.ts b/integration-tests/api/factories/simple-shipping-tax-rate-factory.ts new file mode 100644 index 0000000000..1ce21cdda9 --- /dev/null +++ b/integration-tests/api/factories/simple-shipping-tax-rate-factory.ts @@ -0,0 +1,48 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { ShippingTaxRate, TaxRate } from "@medusajs/medusa" + +type RateFactoryData = { + region_id: string + rate?: number | null + code?: string + name?: string +} + +export type ShippingTaxRateFactoryData = { + shipping_option_id: string + rate: RateFactoryData | string +} + +export const simpleShippingTaxRateFactory = async ( + connection: Connection, + data: ShippingTaxRateFactoryData, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + let rateId: string + if (typeof data.rate === "string") { + rateId = data.rate + } else { + const newRate = manager.create(TaxRate, { + region_id: data.rate.region_id, + rate: data.rate.rate, + code: data.rate.code || "sales_tax", + name: data.rate.name || "Sales Tax", + }) + const rate = await manager.save(newRate) + rateId = rate.id + } + + const toSave = manager.create(ShippingTaxRate, { + shipping_option_id: data.shipping_option_id, + rate_id: rateId, + }) + + return await manager.save(toSave) +} diff --git a/integration-tests/api/factories/simple-tax-rate-factory.ts b/integration-tests/api/factories/simple-tax-rate-factory.ts new file mode 100644 index 0000000000..44987da67e --- /dev/null +++ b/integration-tests/api/factories/simple-tax-rate-factory.ts @@ -0,0 +1,32 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { TaxRate } from "@medusajs/medusa" + +export type TaxRateFactoryData = { + region_id: string + rate?: number | null + code?: string + name?: string +} + +export const simpleTaxRateFactory = async ( + connection: Connection, + data: TaxRateFactoryData, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + const toSave = manager.create(TaxRate, { + region_id: data.region_id, + rate: + data.rate ?? faker.datatype.number({ min: 0, max: 100, precision: 2 }), + code: data.code || faker.random.word(), + name: data.name || faker.random.words(2), + }) + + return await manager.save(toSave) +} diff --git a/integration-tests/api/package.json b/integration-tests/api/package.json index e6b6b1c71c..d512574b8b 100644 --- a/integration-tests/api/package.json +++ b/integration-tests/api/package.json @@ -8,8 +8,9 @@ "build": "babel src -d dist --extensions \".ts,.js\"" }, "dependencies": { - "@medusajs/medusa": "1.1.64-dev-1645441522984", - "medusa-interfaces": "1.1.34-dev-1645441522984", + "@medusajs/medusa": "1.1.64-dev-1645628651544", + "faker": "^5.5.3", + "medusa-interfaces": "1.1.34-dev-1645628651544", "typeorm": "^0.2.31" }, "devDependencies": { diff --git a/integration-tests/api/src/services/test-pay.js b/integration-tests/api/src/services/test-pay.js index 7536c45a45..eed8aa80e5 100644 --- a/integration-tests/api/src/services/test-pay.js +++ b/integration-tests/api/src/services/test-pay.js @@ -15,8 +15,22 @@ class TestPayService extends PaymentService { return Promise.resolve([]) } - async createPayment() { - return {} + async createPayment(cart) { + const fields = [ + "total", + "subtotal", + "tax_total", + "discount_total", + "shipping_total", + "gift_card_total", + ] + + const data = {} + for (const k of fields) { + data[k] = cart[k] + } + + return data } async retrievePayment(data) { diff --git a/integration-tests/api/yarn.lock b/integration-tests/api/yarn.lock index 979b771916..896242ce63 100644 --- a/integration-tests/api/yarn.lock +++ b/integration-tests/api/yarn.lock @@ -1256,10 +1256,10 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" -"@medusajs/medusa-cli@1.1.27-dev-1645441522984": - version "1.1.27-dev-1645441522984" - resolved "http://localhost:4873/@medusajs%2fmedusa-cli/-/medusa-cli-1.1.27-dev-1645441522984.tgz#e3a5d8430c98592cce7909e1052fb5e2aec6797f" - integrity sha512-NnyH16LliwphtoGHg4phJBHFmtbt8I6tI9gs1ora2J/1gbZZbl5bjn9LG5MGZrCye69OBb1UdTWB+UWROgTBzg== +"@medusajs/medusa-cli@1.1.27-dev-1645628651544": + version "1.1.27-dev-1645628651544" + resolved "http://localhost:4873/@medusajs%2fmedusa-cli/-/medusa-cli-1.1.27-dev-1645628651544.tgz#0b5531d3c0df9a6a9ea01990b53f751692439458" + integrity sha512-3NrmJwIiUyLB/mYhVY0vUzrsFqHBCV+8LF+mrRwYWlsixXT8muSVUpObPJtvSRG4D/6xQrKcFk9wreDoT+Az9w== dependencies: "@babel/polyfill" "^7.8.7" "@babel/runtime" "^7.9.6" @@ -1277,8 +1277,8 @@ is-valid-path "^0.1.1" joi-objectid "^3.0.1" meant "^1.0.1" - medusa-core-utils "1.1.31-dev-1645441522984" - medusa-telemetry "0.0.11-dev-1645441522984" + medusa-core-utils "1.1.31-dev-1645628651544" + medusa-telemetry "0.0.11-dev-1645628651544" netrc-parser "^3.1.6" open "^8.0.6" ora "^5.4.1" @@ -1292,13 +1292,13 @@ winston "^3.3.3" yargs "^15.3.1" -"@medusajs/medusa@1.1.64-dev-1645441522984": - version "1.1.64-dev-1645441522984" - resolved "http://localhost:4873/@medusajs%2fmedusa/-/medusa-1.1.64-dev-1645441522984.tgz#46dda1904705f2adb15e8aaafe0e1ecdce09763d" - integrity sha512-oQkdKGRhpa504vBhAmdRZMRxD1HUnXA6l0amaIeHk7OpT8JewMt63f/G6nttXatkHUNcYV0tlRW+mgy1gAyAmA== +"@medusajs/medusa@1.1.64-dev-1645628651544": + version "1.1.64-dev-1645628651544" + resolved "http://localhost:4873/@medusajs%2fmedusa/-/medusa-1.1.64-dev-1645628651544.tgz#d4e314cc8511d337bf380cdf0d3714b3ab039298" + integrity sha512-h2A1V96bJzMn1pe0jhQ98J4b8tv1JUGUQV3vYNIjHLKrWQVVNoY52Rk8bQjaCyH9YoITbiLOSRTApTSUsqzpyQ== dependencies: "@hapi/joi" "^16.1.8" - "@medusajs/medusa-cli" "1.1.27-dev-1645441522984" + "@medusajs/medusa-cli" "1.1.27-dev-1645628651544" "@types/lodash" "^4.14.168" awilix "^4.2.3" body-parser "^1.19.0" @@ -1322,8 +1322,8 @@ joi "^17.3.0" joi-objectid "^3.0.1" jsonwebtoken "^8.5.1" - medusa-core-utils "1.1.31-dev-1645441522984" - medusa-test-utils "1.1.37-dev-1645441522984" + medusa-core-utils "1.1.31-dev-1645628651544" + medusa-test-utils "1.1.37-dev-1645628651544" morgan "^1.9.1" multer "^1.4.2" passport "^0.4.0" @@ -1947,10 +1947,10 @@ babel-preset-jest@^26.6.2: babel-plugin-jest-hoist "^26.6.2" babel-preset-current-node-syntax "^1.0.0" -babel-preset-medusa-package@1.1.19-dev-1645441522984: - version "1.1.19-dev-1645441522984" - resolved "http://localhost:4873/babel-preset-medusa-package/-/babel-preset-medusa-package-1.1.19-dev-1645441522984.tgz#d7f494e6bcdf97d22e32913809a842d90720ee71" - integrity sha512-slmfLD+uwJhvYz2MMwFepjpbBB6K4EaZbKImJJ/Bp4RcZzoc44lCV/e5+9q2HU7hz+aLgZVangFvL9vLXglyzQ== +babel-preset-medusa-package@1.1.19-dev-1645628651544: + version "1.1.19-dev-1645628651544" + resolved "http://localhost:4873/babel-preset-medusa-package/-/babel-preset-medusa-package-1.1.19-dev-1645628651544.tgz#506bd183276d30458da4e2857459c6f38435d4b0" + integrity sha512-0XBmV1OuUDVIQccYKfU3Yj2gMYIeLEV8I/ugyVfgQ4AiYU7to97wFzdD8dXUTXd1I94gw4jbyZeZwflj0NoMhw== dependencies: "@babel/plugin-proposal-class-properties" "^7.12.1" "@babel/plugin-proposal-decorators" "^7.12.1" @@ -3265,6 +3265,11 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== +faker@^5.5.3: + version "5.5.3" + resolved "https://registry.yarnpkg.com/faker/-/faker-5.5.3.tgz#c57974ee484431b25205c2c8dc09fda861e51e0e" + integrity sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g== + fast-deep-equal@^3.1.1: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -5135,25 +5140,25 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= -medusa-core-utils@1.1.31-dev-1645441522984: - version "1.1.31-dev-1645441522984" - resolved "http://localhost:4873/medusa-core-utils/-/medusa-core-utils-1.1.31-dev-1645441522984.tgz#e8942d486689b3fa5b2dcdd6b98cb7f2a46ffc3a" - integrity sha512-BRQf/vQoiHbRfEty1vSqcX5rbiQaoeYigiParQMmD3fnRprrKkxh9UjsPzVckiyjLM2QU4NIPcve42HmCJ+iKA== +medusa-core-utils@1.1.31-dev-1645628651544: + version "1.1.31-dev-1645628651544" + resolved "http://localhost:4873/medusa-core-utils/-/medusa-core-utils-1.1.31-dev-1645628651544.tgz#bd6c5dc2aec5f9a109afef8eee22cbef1c77d63c" + integrity sha512-xkLY5QPcM1yjvhhSv39zJX9RimCMS7p8Y3j9ey6JrZYXBwzznzKsDPTlhZAdNKZuvGXVvnnmJXh563fvS8lGlg== dependencies: joi "^17.3.0" joi-objectid "^3.0.1" -medusa-interfaces@1.1.34-dev-1645441522984: - version "1.1.34-dev-1645441522984" - resolved "http://localhost:4873/medusa-interfaces/-/medusa-interfaces-1.1.34-dev-1645441522984.tgz#81522e69f2416916a4a134263db62f73dc4c00c0" - integrity sha512-1IMOtBJvCwPh4pscOn7Z9c+vOkebadHu8AB9KbwWRM3ziyYgwNMVg8tC90sn20PctDXeQyWhsPfY1IkWj83WXw== +medusa-interfaces@1.1.34-dev-1645628651544: + version "1.1.34-dev-1645628651544" + resolved "http://localhost:4873/medusa-interfaces/-/medusa-interfaces-1.1.34-dev-1645628651544.tgz#6d19acdef4019813eaa7554721cbc4f02fb16083" + integrity sha512-QsP0CtriL0avWFtSWtFoLx1oAcMtgMKAyCIfkkRQuPLYtM0o7Rc1l4cMnvYw9I8XPw+/RFQnc0CL3vJqDVzEUQ== dependencies: - medusa-core-utils "1.1.31-dev-1645441522984" + medusa-core-utils "1.1.31-dev-1645628651544" -medusa-telemetry@0.0.11-dev-1645441522984: - version "0.0.11-dev-1645441522984" - resolved "http://localhost:4873/medusa-telemetry/-/medusa-telemetry-0.0.11-dev-1645441522984.tgz#6939f21cbf01015df6d59983cfdfebc4d853d781" - integrity sha512-l2kYVlYYs0tMIy27xCyj1USfh0yE8L9i+c8j0jW6mqcAJ+rVMPrahBs4jQs8TD1ptFtLDgYUNRg4WK1/f6RN8Q== +medusa-telemetry@0.0.11-dev-1645628651544: + version "0.0.11-dev-1645628651544" + resolved "http://localhost:4873/medusa-telemetry/-/medusa-telemetry-0.0.11-dev-1645628651544.tgz#b1534c1e52d699f10cd66cdb270f04217d8aba56" + integrity sha512-+IkNVi75gogVyXTL4dDSYY+3g26B69yljQDH6XOqwNSb8OXU/XBxmv6EiHzjopESe82caXr8kUnyFWOyybp9VA== dependencies: axios "^0.21.1" axios-retry "^3.1.9" @@ -5165,13 +5170,13 @@ medusa-telemetry@0.0.11-dev-1645441522984: remove-trailing-slash "^0.1.1" uuid "^8.3.2" -medusa-test-utils@1.1.37-dev-1645441522984: - version "1.1.37-dev-1645441522984" - resolved "http://localhost:4873/medusa-test-utils/-/medusa-test-utils-1.1.37-dev-1645441522984.tgz#14e197adaab890e0aa1bbe812d8dd51387e38661" - integrity sha512-5qfcgPA/usM+n9vUoZluK0rEldaz5movukqDeyPTI1YbhJpIjQAq2f8GkHPIORDg4ppawUYz93d3gchIhe87FA== +medusa-test-utils@1.1.37-dev-1645628651544: + version "1.1.37-dev-1645628651544" + resolved "http://localhost:4873/medusa-test-utils/-/medusa-test-utils-1.1.37-dev-1645628651544.tgz#45103cf82131b41d073e17188f9b7f5985b4c083" + integrity sha512-56OByKGpTGnFQ6ThEadThovK5+h/24/CTBOvBCq/voOmwxsr89LBTwd9UB7wbubb6L/voMWSfmOsCb/7kUkq6w== dependencies: "@babel/plugin-transform-classes" "^7.9.5" - medusa-core-utils "1.1.31-dev-1645441522984" + medusa-core-utils "1.1.31-dev-1645628651544" randomatic "^3.1.1" merge-descriptors@1.0.1: diff --git a/integration-tests/helpers/bootstrap-app.js b/integration-tests/helpers/bootstrap-app.js new file mode 100644 index 0000000000..0dc1c221e2 --- /dev/null +++ b/integration-tests/helpers/bootstrap-app.js @@ -0,0 +1,30 @@ +const path = require("path") +const express = require("express") +const getPort = require("get-port") +const importFrom = require("import-from") + +module.exports = { + bootstrapApp: async ({ cwd } = {}) => { + const app = express() + + const loaders = importFrom( + cwd || process.cwd(), + "@medusajs/medusa/dist/loaders" + ).default + + const { container, dbConnection } = await loaders({ + directory: path.resolve(cwd || process.cwd()), + expressApp: app, + isTest: false, + }) + + const PORT = await getPort() + + return { + container, + db: dbConnection, + app, + port: PORT, + } + }, +} diff --git a/integration-tests/helpers/test-server.js b/integration-tests/helpers/test-server.js index 7feb62d855..2282ab2127 100644 --- a/integration-tests/helpers/test-server.js +++ b/integration-tests/helpers/test-server.js @@ -1,32 +1,7 @@ -const path = require("path") -const express = require("express") -const getPort = require("get-port") -const importFrom = require("import-from") - -const initialize = async () => { - const app = express() - - const loaders = importFrom( - process.cwd(), - "@medusajs/medusa/dist/loaders" - ).default - - const { dbConnection } = await loaders({ - directory: path.resolve(process.cwd()), - expressApp: app, - }) - - const PORT = await getPort() - - return { - db: dbConnection, - app, - port: PORT, - } -} +const { bootstrapApp } = require("./bootstrap-app") const setup = async () => { - const { app, port } = await initialize() + const { app, port } = await bootstrapApp() app.listen(port, (err) => { process.send(port) diff --git a/integration-tests/helpers/use-db.js b/integration-tests/helpers/use-db.js index 10e70c9783..5fb1d64c58 100644 --- a/integration-tests/helpers/use-db.js +++ b/integration-tests/helpers/use-db.js @@ -16,6 +16,7 @@ const pgGodCredentials = { } const keepTables = [ + "store", "staged_job", "shipping_profile", "fulfillment_provider", @@ -37,7 +38,9 @@ const DbTestUtil = { this.db_.synchronize(true) }, - teardown: async function () { + teardown: async function ({ forceDelete } = {}) { + forceDelete = forceDelete || [] + const entities = this.db_.entityMetadatas const manager = this.db_.manager @@ -48,7 +51,10 @@ const DbTestUtil = { } for (const entity of entities) { - if (keepTables.includes(entity.tableName)) { + if ( + keepTables.includes(entity.tableName) && + !forceDelete.includes(entity.tableName) + ) { continue } diff --git a/integration-tests/jest.config.js b/integration-tests/jest.config.js index 1063e4faf1..fd751bd3ac 100644 --- a/integration-tests/jest.config.js +++ b/integration-tests/jest.config.js @@ -15,6 +15,7 @@ module.exports = { `/www/`, `/dist/`, `/node_modules/`, + `/plugins/`, `__tests__/fixtures`, `__testfixtures__`, `.cache`, diff --git a/integration-tests/package.json b/integration-tests/package.json index da071ad62c..d8f79fc5b8 100644 --- a/integration-tests/package.json +++ b/integration-tests/package.json @@ -10,5 +10,8 @@ "license": "ISC", "devDependencies": { "dotenv": "^10.0.0" + }, + "dependencies": { + "@faker-js/faker": "^5.5.3" } } diff --git a/integration-tests/plugins/.babelrc.js b/integration-tests/plugins/.babelrc.js new file mode 100644 index 0000000000..bde709c495 --- /dev/null +++ b/integration-tests/plugins/.babelrc.js @@ -0,0 +1,13 @@ +let ignore = [`**/dist`] + +// Jest needs to compile this code, but generally we don't want this copied +// to output folders +if (process.env.NODE_ENV !== `test`) { + ignore.push(`**/__tests__`) +} + +module.exports = { + sourceMaps: true, + presets: ["babel-preset-medusa-package"], + ignore, +} diff --git a/integration-tests/plugins/.gitignore b/integration-tests/plugins/.gitignore new file mode 100644 index 0000000000..a2c424c876 --- /dev/null +++ b/integration-tests/plugins/.gitignore @@ -0,0 +1,4 @@ +dist/ +node_modules +*yarn-error.log + diff --git a/integration-tests/plugins/__tests__/medusa-plugin-sendgrid/__snapshots__/index.js.snap b/integration-tests/plugins/__tests__/medusa-plugin-sendgrid/__snapshots__/index.js.snap new file mode 100644 index 0000000000..131147d241 --- /dev/null +++ b/integration-tests/plugins/__tests__/medusa-plugin-sendgrid/__snapshots__/index.js.snap @@ -0,0 +1,2444 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`medusa-plugin-sendgrid claim shipment created data 1`] = ` +Object { + "claim": Object { + "canceled_at": null, + "created_at": Any, + "deleted_at": null, + "fulfillment_status": "shipped", + "id": Any, + "idempotency_key": Any, + "metadata": null, + "no_notification": null, + "order": Object { + "billing_address_id": null, + "canceled_at": null, + "cart_id": null, + "created_at": Any, + "currency_code": "usd", + "customer_id": Any, + "display_id": Any, + "draft_order_id": null, + "email": "test@testson.com", + "external_id": null, + "fulfillment_status": "fulfilled", + "id": Any, + "idempotency_key": null, + "items": Array [ + Object { + "allow_discounts": true, + "cart_id": null, + "claim_order_id": null, + "created_at": Any, + "description": "", + "fulfilled_quantity": 2, + "has_shipping": null, + "id": Any, + "is_giftcard": false, + "is_return": false, + "metadata": null, + "order_id": Any, + "quantity": 2, + "returned_quantity": null, + "shipped_quantity": 2, + "should_merge": true, + "swap_id": null, + "thumbnail": "", + "title": "Intelligent Plastic Chips", + "unit_price": 1000, + "updated_at": Any, + "variant": Object { + "allow_backorder": false, + "barcode": null, + "created_at": Any, + "deleted_at": null, + "ean": null, + "height": null, + "hs_code": null, + "id": "test-variant", + "inventory_quantity": 10, + "length": null, + "manage_inventory": true, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "product": Object { + "collection_id": null, + "created_at": Any, + "deleted_at": null, + "description": null, + "discountable": true, + "external_id": null, + "handle": null, + "height": null, + "hs_code": null, + "id": "test-product", + "is_giftcard": false, + "length": null, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "profile_id": Any, + "status": "draft", + "subtitle": null, + "thumbnail": null, + "title": "Awesome Metal Ball", + "type_id": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "product_id": "test-product", + "sku": null, + "title": "Practical Granite Pizza", + "upc": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "variant_id": "test-variant", + }, + ], + "metadata": null, + "no_notification": null, + "object": "order", + "payment_status": "captured", + "region_id": "test-region", + "shipping_address": Object { + "address_1": "84185 Lindsey Centers", + "address_2": null, + "city": null, + "company": null, + "country_code": "us", + "created_at": Any, + "customer_id": null, + "deleted_at": null, + "first_name": "Chyna", + "id": Any, + "last_name": "Osinski", + "metadata": null, + "phone": null, + "postal_code": "51510", + "province": null, + "updated_at": Any, + }, + "shipping_address_id": Any, + "status": "pending", + "tax_rate": null, + "updated_at": Any, + }, + "order_id": Any, + "payment_status": "na", + "refund_amount": null, + "shipping_address_id": Any, + "type": "replace", + "updated_at": Any, + }, + "email": "test@testson.com", + "fulfillment": Object { + "canceled_at": null, + "claim_order_id": Any, + "created_at": Any, + "data": Object {}, + "id": Any, + "idempotency_key": null, + "items": Array [ + Object { + "fulfillment_id": Any, + "item_id": Any, + "quantity": 1, + }, + ], + "metadata": Object {}, + "no_notification": null, + "order_id": null, + "provider_id": "test-ful", + "shipped_at": Any, + "swap_id": null, + "tracking_links": Array [], + "tracking_numbers": Array [], + "updated_at": Any, + }, + "locale": null, + "order": Object { + "billing_address_id": null, + "canceled_at": null, + "cart_id": null, + "created_at": Any, + "currency_code": "usd", + "customer_id": Any, + "display_id": Any, + "draft_order_id": null, + "email": "test@testson.com", + "external_id": null, + "fulfillment_status": "fulfilled", + "id": Any, + "idempotency_key": null, + "items": Array [ + Object { + "allow_discounts": true, + "cart_id": null, + "claim_order_id": null, + "created_at": Any, + "description": "", + "fulfilled_quantity": 2, + "has_shipping": null, + "id": Any, + "is_giftcard": false, + "is_return": false, + "metadata": null, + "order_id": Any, + "quantity": 2, + "returned_quantity": null, + "shipped_quantity": 2, + "should_merge": true, + "swap_id": null, + "thumbnail": "", + "title": "Intelligent Plastic Chips", + "unit_price": 1000, + "updated_at": Any, + "variant": Object { + "allow_backorder": false, + "barcode": null, + "created_at": Any, + "deleted_at": null, + "ean": null, + "height": null, + "hs_code": null, + "id": "test-variant", + "inventory_quantity": 10, + "length": null, + "manage_inventory": true, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "product": Object { + "collection_id": null, + "created_at": Any, + "deleted_at": null, + "description": null, + "discountable": true, + "external_id": null, + "handle": null, + "height": null, + "hs_code": null, + "id": "test-product", + "is_giftcard": false, + "length": null, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "profile_id": Any, + "status": "draft", + "subtitle": null, + "thumbnail": null, + "title": "Awesome Metal Ball", + "type_id": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "product_id": "test-product", + "sku": null, + "title": "Practical Granite Pizza", + "upc": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "variant_id": "test-variant", + }, + ], + "metadata": null, + "no_notification": null, + "object": "order", + "payment_status": "captured", + "region_id": "test-region", + "shipping_address": Object { + "address_1": "84185 Lindsey Centers", + "address_2": null, + "city": null, + "company": null, + "country_code": "us", + "created_at": Any, + "customer_id": null, + "deleted_at": null, + "first_name": "Chyna", + "id": Any, + "last_name": "Osinski", + "metadata": null, + "phone": null, + "postal_code": "51510", + "province": null, + "updated_at": Any, + }, + "shipping_address_id": Any, + "status": "pending", + "tax_rate": null, + "updated_at": Any, + }, + "tracking_links": Array [], + "tracking_number": "", +} +`; + +exports[`medusa-plugin-sendgrid items returned data 1`] = ` +Object { + "date": Any, + "email": "test@testson.com", + "has_shipping": false, + "items": Array [ + Object { + "allow_discounts": true, + "cart_id": null, + "claim_order_id": null, + "created_at": Any, + "description": "", + "fulfilled_quantity": 2, + "has_shipping": null, + "id": Any, + "is_giftcard": false, + "is_return": false, + "metadata": null, + "order_id": Any, + "price": "12.00 USD", + "quantity": 1, + "returned_quantity": 1, + "shipped_quantity": 2, + "should_merge": true, + "swap_id": null, + "tax_lines": Array [ + Object { + "code": "default", + "created_at": Any, + "id": Any, + "item_id": "test-item", + "metadata": null, + "name": "default", + "rate": 20, + "updated_at": Any, + }, + ], + "thumbnail": null, + "title": "Intelligent Plastic Chips", + "totals": Object { + "discount_total": 0, + "gift_card_total": 0, + "original_tax_total": 200, + "original_total": 1200, + "quantity": 1, + "subtotal": 1000, + "tax_lines": Array [ + Object { + "code": "default", + "created_at": Any, + "id": Any, + "item_id": "test-item", + "metadata": null, + "name": "default", + "rate": 20, + "updated_at": Any, + }, + ], + "tax_total": 200, + "total": 1200, + "unit_price": 1000, + }, + "unit_price": 1000, + "updated_at": Any, + "variant": Object { + "allow_backorder": false, + "barcode": null, + "created_at": Any, + "deleted_at": null, + "ean": null, + "height": null, + "hs_code": null, + "id": "test-variant", + "inventory_quantity": 11, + "length": null, + "manage_inventory": true, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "product": Object { + "collection_id": null, + "created_at": Any, + "deleted_at": null, + "description": null, + "discountable": true, + "external_id": null, + "handle": null, + "height": null, + "hs_code": null, + "id": "test-product", + "is_giftcard": false, + "length": null, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "profile_id": Any, + "status": "draft", + "subtitle": null, + "thumbnail": null, + "title": "Awesome Metal Ball", + "type_id": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "product_id": "test-product", + "sku": null, + "title": "Practical Granite Pizza", + "upc": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "variant_id": "test-variant", + }, + ], + "locale": null, + "order": Object { + "beforeInsert": [Function], + "billing_address_id": null, + "canceled_at": null, + "cart_id": null, + "claims": Array [], + "created_at": Any, + "currency_code": "usd", + "customer_id": Any, + "discounts": Array [], + "display_id": Any, + "draft_order_id": null, + "email": "test@testson.com", + "external_id": null, + "fulfillment_status": "requires_action", + "gift_card_transactions": Array [], + "gift_cards": Array [], + "id": Any, + "idempotency_key": null, + "items": Array [ + Object { + "allow_discounts": true, + "cart_id": null, + "claim_order_id": null, + "created_at": Any, + "description": "", + "fulfilled_quantity": 2, + "has_shipping": null, + "id": Any, + "is_giftcard": false, + "is_return": false, + "metadata": null, + "order_id": Any, + "quantity": 2, + "returned_quantity": 1, + "shipped_quantity": 2, + "should_merge": true, + "swap_id": null, + "tax_lines": Array [ + Object { + "code": "default", + "created_at": Any, + "id": Any, + "item_id": "test-item", + "metadata": null, + "name": "default", + "rate": 20, + "updated_at": Any, + }, + ], + "thumbnail": "", + "title": "Intelligent Plastic Chips", + "unit_price": 1000, + "updated_at": Any, + "variant": Object { + "allow_backorder": false, + "barcode": null, + "created_at": Any, + "deleted_at": null, + "ean": null, + "height": null, + "hs_code": null, + "id": "test-variant", + "inventory_quantity": 11, + "length": null, + "manage_inventory": true, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "product": Object { + "collection_id": null, + "created_at": Any, + "deleted_at": null, + "description": null, + "discountable": true, + "external_id": null, + "handle": null, + "height": null, + "hs_code": null, + "id": "test-product", + "is_giftcard": false, + "length": null, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "profile_id": Any, + "status": "draft", + "subtitle": null, + "thumbnail": null, + "title": "Awesome Metal Ball", + "type_id": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "product_id": "test-product", + "sku": null, + "title": "Practical Granite Pizza", + "upc": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "variant_id": "test-variant", + }, + ], + "metadata": null, + "no_notification": null, + "object": "order", + "payment_status": "captured", + "refunds": Array [], + "region": Object { + "automatic_taxes": true, + "created_at": Any, + "currency_code": "usd", + "deleted_at": null, + "fulfillment_providers": Array [], + "gift_cards_taxable": true, + "id": Any, + "metadata": null, + "name": "Test region", + "payment_providers": Array [ + PaymentProvider { + "id": "test-pay", + "is_installed": true, + }, + ], + "tax_code": null, + "tax_provider_id": null, + "tax_rate": 12.5, + "updated_at": Any, + }, + "region_id": "test-region", + "returns": Array [ + Object { + "claim_order_id": null, + "created_at": Any, + "id": Any, + "idempotency_key": Any, + "items": Array [ + Object { + "is_requested": true, + "item_id": "test-item", + "metadata": null, + "note": null, + "quantity": 1, + "reason_id": null, + "received_quantity": null, + "requested_quantity": 1, + "return_id": Any, + }, + ], + "metadata": null, + "no_notification": null, + "order_id": Any, + "received_at": Any, + "refund_amount": 1200, + "shipping_data": null, + "status": "received", + "swap_id": null, + "updated_at": Any, + }, + ], + "shipping_address": Object { + "address_1": "84185 Lindsey Centers", + "address_2": null, + "city": null, + "company": null, + "country_code": "us", + "created_at": Any, + "customer_id": null, + "deleted_at": null, + "first_name": "Chyna", + "id": Any, + "last_name": "Osinski", + "metadata": null, + "phone": null, + "postal_code": "51510", + "province": null, + "updated_at": Any, + }, + "shipping_address_id": Any, + "shipping_methods": Array [], + "status": "pending", + "swaps": Array [], + "tax_rate": null, + "total": 2400, + "updated_at": Any, + }, + "refund_amount": "12.00 USD", + "return_request": Object { + "claim_order_id": null, + "created_at": Any, + "id": Any, + "idempotency_key": Any, + "items": Array [ + Object { + "is_requested": true, + "item": Object { + "allow_discounts": true, + "cart_id": null, + "claim_order_id": null, + "created_at": Any, + "description": "", + "fulfilled_quantity": 2, + "has_shipping": null, + "id": Any, + "is_giftcard": false, + "is_return": false, + "metadata": null, + "order_id": Any, + "quantity": 2, + "returned_quantity": 1, + "shipped_quantity": 2, + "should_merge": true, + "swap_id": null, + "tax_lines": Array [ + Object { + "code": "default", + "created_at": Any, + "id": Any, + "item_id": "test-item", + "metadata": null, + "name": "default", + "rate": 20, + "updated_at": Any, + }, + ], + "thumbnail": "", + "title": "Intelligent Plastic Chips", + "unit_price": 1000, + "updated_at": Any, + "variant": Object { + "allow_backorder": false, + "barcode": null, + "created_at": Any, + "deleted_at": null, + "ean": null, + "height": null, + "hs_code": null, + "id": "test-variant", + "inventory_quantity": 11, + "length": null, + "manage_inventory": true, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "product": Object { + "collection_id": null, + "created_at": Any, + "deleted_at": null, + "description": null, + "discountable": true, + "external_id": null, + "handle": null, + "height": null, + "hs_code": null, + "id": "test-product", + "is_giftcard": false, + "length": null, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "profile_id": Any, + "status": "draft", + "subtitle": null, + "thumbnail": null, + "title": "Awesome Metal Ball", + "type_id": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "product_id": "test-product", + "sku": null, + "title": "Practical Granite Pizza", + "upc": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "variant_id": "test-variant", + }, + "item_id": "test-item", + "metadata": null, + "note": null, + "quantity": 1, + "reason_id": null, + "received_quantity": null, + "requested_quantity": 1, + "return_id": Any, + }, + ], + "metadata": null, + "no_notification": null, + "order_id": Any, + "received_at": Any, + "refund_amount": "12.00 USD", + "shipping_data": null, + "shipping_method": null, + "status": "received", + "swap_id": null, + "updated_at": Any, + }, + "shipping_total": "0.00 USD", + "subtotal": "12.00 USD", +} +`; + +exports[`medusa-plugin-sendgrid order canceled data 1`] = ` +Object { + "beforeInsert": [Function], + "billing_address": null, + "billing_address_id": null, + "canceled_at": Any, + "cart_id": null, + "claims": Array [], + "created_at": Any, + "currency_code": "usd", + "customer": Object { + "billing_address_id": null, + "created_at": Any, + "deleted_at": null, + "email": "test@testson.com", + "first_name": null, + "has_account": false, + "id": Any, + "last_name": null, + "metadata": null, + "phone": null, + "updated_at": Any, + }, + "customer_id": Any, + "date": Any, + "discount_total": "0.00 USD", + "discounts": Array [], + "display_id": Any, + "draft_order_id": null, + "email": "test@testson.com", + "external_id": null, + "fulfillment_status": "canceled", + "fulfillments": Array [], + "gift_card_total": "0.00 USD", + "gift_card_transactions": Array [], + "gift_cards": Array [], + "has_discounts": 0, + "has_gift_cards": 0, + "id": Any, + "idempotency_key": null, + "items": Array [ + Object { + "allow_discounts": true, + "cart_id": null, + "claim_order_id": null, + "created_at": Any, + "description": "", + "fulfilled_quantity": null, + "has_shipping": null, + "id": "test-item", + "is_giftcard": false, + "is_return": false, + "metadata": null, + "order_id": Any, + "price": "10.00 USD", + "quantity": 2, + "returned_quantity": null, + "shipped_quantity": null, + "should_merge": true, + "swap_id": null, + "tax_lines": Array [ + Object { + "code": "default", + "created_at": Any, + "id": Any, + "item_id": "test-item", + "metadata": null, + "name": "default", + "rate": 20, + "updated_at": Any, + }, + ], + "thumbnail": null, + "title": "Intelligent Plastic Chips", + "unit_price": 1000, + "updated_at": Any, + "variant": Object { + "allow_backorder": false, + "barcode": null, + "created_at": Any, + "deleted_at": null, + "ean": null, + "height": null, + "hs_code": null, + "id": "test-variant", + "inventory_quantity": 12, + "length": null, + "manage_inventory": true, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "product": Object { + "collection_id": null, + "created_at": Any, + "deleted_at": null, + "description": null, + "discountable": true, + "external_id": null, + "handle": null, + "height": null, + "hs_code": null, + "id": "test-product", + "is_giftcard": false, + "length": null, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "profile_id": Any, + "status": "draft", + "subtitle": null, + "thumbnail": null, + "title": "Awesome Metal Ball", + "type_id": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "product_id": "test-product", + "sku": null, + "title": "Practical Granite Pizza", + "upc": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "variant_id": "test-variant", + }, + ], + "locale": null, + "metadata": null, + "no_notification": null, + "object": "order", + "payment_status": "canceled", + "payments": Array [], + "refunded_total": 0, + "refunds": Array [], + "region": Object { + "automatic_taxes": true, + "created_at": Any, + "currency_code": "usd", + "deleted_at": null, + "fulfillment_providers": Array [], + "gift_cards_taxable": true, + "id": "test-region", + "metadata": null, + "name": "Test region", + "payment_providers": Array [ + PaymentProvider { + "id": "test-pay", + "is_installed": true, + }, + ], + "tax_code": null, + "tax_provider_id": null, + "tax_rate": 12.5, + "updated_at": Any, + }, + "region_id": "test-region", + "returns": Array [], + "shipping_address": Object { + "address_1": "84185 Lindsey Centers", + "address_2": null, + "city": null, + "company": null, + "country_code": "us", + "created_at": Any, + "customer_id": null, + "deleted_at": null, + "first_name": "Chyna", + "id": Any, + "last_name": "Osinski", + "metadata": null, + "phone": null, + "postal_code": "51510", + "province": null, + "updated_at": Any, + }, + "shipping_address_id": Any, + "shipping_methods": Array [ + Object { + "cart_id": null, + "claim_order_id": null, + "data": Object {}, + "id": Any, + "order_id": Any, + "price": 0, + "return_id": null, + "shipping_option": Object { + "admin_only": false, + "amount": 500, + "created_at": Any, + "data": Object {}, + "deleted_at": null, + "id": Any, + "is_return": false, + "metadata": null, + "name": "free", + "price_type": "flat_rate", + "profile_id": Any, + "provider_id": "test-ful", + "region_id": "test-region", + "updated_at": Any, + }, + "shipping_option_id": Any, + "swap_id": null, + "tax_lines": Array [], + }, + ], + "shipping_total": "0.00 USD", + "status": "canceled", + "subtotal": "20.00 USD", + "swaps": Array [], + "tax_rate": null, + "tax_total": "4.00 USD", + "total": "24.00 USD", + "updated_at": Any, +} +`; + +exports[`medusa-plugin-sendgrid order placed data 1`] = ` +Object { + "beforeInsert": [Function], + "billing_address": null, + "billing_address_id": null, + "canceled_at": null, + "cart_id": null, + "claims": Array [], + "created_at": Any, + "currency_code": "usd", + "customer": Object { + "billing_address_id": null, + "created_at": Any, + "deleted_at": null, + "email": "test@testson.com", + "first_name": null, + "has_account": false, + "id": Any, + "last_name": null, + "metadata": null, + "phone": null, + "updated_at": Any, + }, + "customer_id": Any, + "date": Any, + "discount_total": "0.00 USD", + "discounts": Array [], + "display_id": Any, + "draft_order_id": null, + "email": "test@testson.com", + "external_id": null, + "fulfillment_status": "fulfilled", + "fulfillments": Array [], + "gift_card_total": "0.00 USD", + "gift_card_transactions": Array [], + "gift_cards": Array [], + "has_discounts": 0, + "has_gift_cards": 0, + "id": Any, + "idempotency_key": null, + "items": Array [ + Object { + "allow_discounts": true, + "cart_id": null, + "claim_order_id": null, + "created_at": Any, + "description": "", + "discounted_price": "12.00 USD", + "fulfilled_quantity": 2, + "has_shipping": null, + "id": "test-item", + "is_giftcard": false, + "is_return": false, + "metadata": null, + "order_id": Any, + "price": "12.00 USD", + "quantity": 2, + "returned_quantity": null, + "shipped_quantity": 2, + "should_merge": true, + "swap_id": null, + "tax_lines": Array [ + Object { + "code": "default", + "created_at": Any, + "id": Any, + "item_id": "test-item", + "metadata": null, + "name": "default", + "rate": 20, + "updated_at": Any, + }, + ], + "thumbnail": null, + "title": "Intelligent Plastic Chips", + "totals": Object { + "discount_total": 0, + "gift_card_total": 0, + "original_tax_total": 400, + "original_total": 2400, + "quantity": 2, + "subtotal": 2000, + "tax_lines": Array [ + Object { + "code": "default", + "created_at": Any, + "id": Any, + "item_id": "test-item", + "metadata": null, + "name": "default", + "rate": 20, + "updated_at": Any, + }, + ], + "tax_total": 400, + "total": 2400, + "unit_price": 1000, + }, + "unit_price": 1000, + "updated_at": Any, + "variant": Object { + "allow_backorder": false, + "barcode": null, + "created_at": Any, + "deleted_at": null, + "ean": null, + "height": null, + "hs_code": null, + "id": "test-variant", + "inventory_quantity": 10, + "length": null, + "manage_inventory": true, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "product": Object { + "collection_id": null, + "created_at": Any, + "deleted_at": null, + "description": null, + "discountable": true, + "external_id": null, + "handle": null, + "height": null, + "hs_code": null, + "id": "test-product", + "is_giftcard": false, + "length": null, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "profile_id": Any, + "status": "draft", + "subtitle": null, + "thumbnail": null, + "title": "Awesome Metal Ball", + "type_id": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "product_id": "test-product", + "sku": null, + "title": "Practical Granite Pizza", + "upc": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "variant_id": "test-variant", + }, + ], + "locale": null, + "metadata": null, + "no_notification": null, + "object": "order", + "payment_status": "captured", + "payments": Array [], + "refunded_total": 0, + "refunds": Array [], + "region": Object { + "automatic_taxes": true, + "created_at": Any, + "currency_code": "usd", + "deleted_at": null, + "fulfillment_providers": Array [], + "gift_cards_taxable": true, + "id": "test-region", + "metadata": null, + "name": "Test region", + "payment_providers": Array [ + PaymentProvider { + "id": "test-pay", + "is_installed": true, + }, + ], + "tax_code": null, + "tax_provider_id": null, + "tax_rate": 12.5, + "updated_at": Any, + }, + "region_id": "test-region", + "returns": Array [], + "shipping_address": Object { + "address_1": "84185 Lindsey Centers", + "address_2": null, + "city": null, + "company": null, + "country_code": "us", + "created_at": Any, + "customer_id": null, + "deleted_at": null, + "first_name": "Chyna", + "id": Any, + "last_name": "Osinski", + "metadata": null, + "phone": null, + "postal_code": "51510", + "province": null, + "updated_at": Any, + }, + "shipping_address_id": Any, + "shipping_methods": Array [], + "shipping_total": "0.00 USD", + "status": "pending", + "subtotal": "24.00 USD", + "subtotal_ex_tax": "20.00 USD", + "swaps": Array [], + "tax_rate": null, + "tax_total": "4.00 USD", + "total": "24.00 USD", + "updated_at": Any, +} +`; + +exports[`medusa-plugin-sendgrid order shipment created data 1`] = ` +Object { + "date": Any, + "email": "test@testson.com", + "fulfillment": Object { + "canceled_at": null, + "claim_order_id": null, + "created_at": Any, + "data": Object {}, + "id": Any, + "idempotency_key": null, + "items": Array [ + Object { + "fulfillment_id": Any, + "item_id": "test-item", + "quantity": 2, + }, + ], + "metadata": Object {}, + "no_notification": null, + "order_id": Any, + "provider_id": "test-ful", + "shipped_at": Any, + "swap_id": null, + "tracking_links": Array [], + "tracking_numbers": Array [], + "updated_at": Any, + }, + "locale": null, + "order": Object { + "beforeInsert": [Function], + "billing_address": null, + "billing_address_id": null, + "canceled_at": null, + "cart_id": null, + "claims": Array [], + "created_at": Any, + "currency_code": "usd", + "customer": Object { + "billing_address_id": null, + "created_at": Any, + "deleted_at": null, + "email": "test@testson.com", + "first_name": null, + "has_account": false, + "id": Any, + "last_name": null, + "metadata": null, + "phone": null, + "updated_at": Any, + }, + "customer_id": Any, + "discount_total": 0, + "discounts": Array [], + "display_id": Any, + "draft_order_id": null, + "email": "test@testson.com", + "external_id": null, + "fulfillment_status": "shipped", + "fulfillments": Array [ + Object { + "canceled_at": null, + "claim_order_id": null, + "created_at": Any, + "data": Object {}, + "id": Any, + "idempotency_key": null, + "items": Array [ + Object { + "fulfillment_id": Any, + "item_id": "test-item", + "quantity": 2, + }, + ], + "metadata": Object {}, + "no_notification": null, + "order_id": Any, + "provider_id": "test-ful", + "shipped_at": Any, + "swap_id": null, + "tracking_numbers": Array [], + "updated_at": Any, + }, + ], + "gift_card_total": 0, + "gift_card_transactions": Array [], + "gift_cards": Array [], + "id": Any, + "idempotency_key": null, + "items": Array [ + Object { + "allow_discounts": true, + "cart_id": null, + "claim_order_id": null, + "created_at": Any, + "description": "", + "fulfilled_quantity": 2, + "has_shipping": null, + "id": "test-item", + "is_giftcard": false, + "is_return": false, + "metadata": null, + "order_id": Any, + "quantity": 2, + "returned_quantity": null, + "shipped_quantity": 2, + "should_merge": true, + "swap_id": null, + "tax_lines": Array [ + Object { + "code": "default", + "created_at": Any, + "id": Any, + "item_id": "test-item", + "metadata": null, + "name": "default", + "rate": 20, + "updated_at": Any, + }, + ], + "thumbnail": "", + "title": "Intelligent Plastic Chips", + "unit_price": 1000, + "updated_at": Any, + "variant": Object { + "allow_backorder": false, + "barcode": null, + "created_at": Any, + "deleted_at": null, + "ean": null, + "height": null, + "hs_code": null, + "id": "test-variant", + "inventory_quantity": 10, + "length": null, + "manage_inventory": true, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "product": Object { + "collection_id": null, + "created_at": Any, + "deleted_at": null, + "description": null, + "discountable": true, + "external_id": null, + "handle": null, + "height": null, + "hs_code": null, + "id": "test-product", + "is_giftcard": false, + "length": null, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "profile_id": Any, + "status": "draft", + "subtitle": null, + "thumbnail": null, + "title": "Awesome Metal Ball", + "type_id": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "product_id": "test-product", + "sku": null, + "title": "Practical Granite Pizza", + "upc": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "variant_id": "test-variant", + }, + ], + "metadata": null, + "no_notification": null, + "object": "order", + "payment_status": "captured", + "payments": Array [], + "refundable_amount": 0, + "refunded_total": 0, + "refunds": Array [], + "region": Object { + "automatic_taxes": true, + "created_at": Any, + "currency_code": "usd", + "deleted_at": null, + "fulfillment_providers": Array [], + "gift_cards_taxable": true, + "id": "test-region", + "metadata": null, + "name": "Test region", + "payment_providers": Array [ + PaymentProvider { + "id": "test-pay", + "is_installed": true, + }, + ], + "tax_code": null, + "tax_provider_id": null, + "tax_rate": 12.5, + "updated_at": Any, + }, + "region_id": "test-region", + "returns": Array [], + "shipping_address": Object { + "address_1": "84185 Lindsey Centers", + "address_2": null, + "city": null, + "company": null, + "country_code": "us", + "created_at": Any, + "customer_id": null, + "deleted_at": null, + "first_name": "Chyna", + "id": Any, + "last_name": "Osinski", + "metadata": null, + "phone": null, + "postal_code": "51510", + "province": null, + "updated_at": Any, + }, + "shipping_address_id": Any, + "shipping_methods": Array [ + Object { + "cart_id": null, + "claim_order_id": null, + "data": Object {}, + "id": Any, + "order_id": Any, + "price": 0, + "return_id": null, + "shipping_option": Object { + "admin_only": false, + "amount": 500, + "created_at": Any, + "data": Object {}, + "deleted_at": null, + "id": Any, + "is_return": false, + "metadata": null, + "name": "free", + "price_type": "flat_rate", + "profile_id": Any, + "provider_id": "test-ful", + "region_id": "test-region", + "updated_at": Any, + }, + "shipping_option_id": Any, + "swap_id": null, + "tax_lines": Array [], + }, + ], + "shipping_total": 0, + "status": "pending", + "subtotal": 2000, + "swaps": Array [], + "tax_rate": null, + "tax_total": 400, + "total": 2400, + "updated_at": Any, + }, + "tracking_links": Array [], + "tracking_number": "", +} +`; + +exports[`medusa-plugin-sendgrid return requested data 1`] = ` +Object { + "date": Any, + "email": "test@testson.com", + "has_shipping": false, + "items": Array [ + Object { + "allow_discounts": true, + "cart_id": null, + "claim_order_id": null, + "created_at": Any, + "description": "", + "fulfilled_quantity": 2, + "has_shipping": null, + "id": Any, + "is_giftcard": false, + "is_return": false, + "metadata": null, + "order_id": Any, + "price": "12.00 USD", + "quantity": 1, + "returned_quantity": null, + "shipped_quantity": 2, + "should_merge": true, + "swap_id": null, + "tax_lines": Array [ + Object { + "code": "default", + "created_at": Any, + "id": Any, + "item_id": "test-item", + "metadata": null, + "name": "default", + "rate": 20, + "updated_at": Any, + }, + ], + "thumbnail": null, + "title": "Intelligent Plastic Chips", + "totals": Object { + "discount_total": 0, + "gift_card_total": 0, + "original_tax_total": 200, + "original_total": 1200, + "quantity": 1, + "subtotal": 1000, + "tax_lines": Array [ + Object { + "code": "default", + "created_at": Any, + "id": Any, + "item_id": "test-item", + "metadata": null, + "name": "default", + "rate": 20, + "updated_at": Any, + }, + ], + "tax_total": 200, + "total": 1200, + "unit_price": 1000, + }, + "unit_price": 1000, + "updated_at": Any, + "variant": Object { + "allow_backorder": false, + "barcode": null, + "created_at": Any, + "deleted_at": null, + "ean": null, + "height": null, + "hs_code": null, + "id": "test-variant", + "inventory_quantity": 10, + "length": null, + "manage_inventory": true, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "product": Object { + "collection_id": null, + "created_at": Any, + "deleted_at": null, + "description": null, + "discountable": true, + "external_id": null, + "handle": null, + "height": null, + "hs_code": null, + "id": "test-product", + "is_giftcard": false, + "length": null, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "profile_id": Any, + "status": "draft", + "subtitle": null, + "thumbnail": null, + "title": "Awesome Metal Ball", + "type_id": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "product_id": "test-product", + "sku": null, + "title": "Practical Granite Pizza", + "upc": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "variant_id": "test-variant", + }, + ], + "locale": null, + "order": Object { + "beforeInsert": [Function], + "billing_address_id": null, + "canceled_at": null, + "cart_id": null, + "claims": Array [], + "created_at": Any, + "currency_code": "usd", + "customer_id": Any, + "discounts": Array [], + "display_id": Any, + "draft_order_id": null, + "email": "test@testson.com", + "external_id": null, + "fulfillment_status": "fulfilled", + "gift_card_transactions": Array [], + "gift_cards": Array [], + "id": Any, + "idempotency_key": null, + "items": Array [ + Object { + "allow_discounts": true, + "cart_id": null, + "claim_order_id": null, + "created_at": Any, + "description": "", + "fulfilled_quantity": 2, + "has_shipping": null, + "id": Any, + "is_giftcard": false, + "is_return": false, + "metadata": null, + "order_id": Any, + "quantity": 2, + "returned_quantity": null, + "shipped_quantity": 2, + "should_merge": true, + "swap_id": null, + "tax_lines": Array [ + Object { + "code": "default", + "created_at": Any, + "id": Any, + "item_id": "test-item", + "metadata": null, + "name": "default", + "rate": 20, + "updated_at": Any, + }, + ], + "thumbnail": "", + "title": "Intelligent Plastic Chips", + "unit_price": 1000, + "updated_at": Any, + "variant": Object { + "allow_backorder": false, + "barcode": null, + "created_at": Any, + "deleted_at": null, + "ean": null, + "height": null, + "hs_code": null, + "id": "test-variant", + "inventory_quantity": 10, + "length": null, + "manage_inventory": true, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "product": Object { + "collection_id": null, + "created_at": Any, + "deleted_at": null, + "description": null, + "discountable": true, + "external_id": null, + "handle": null, + "height": null, + "hs_code": null, + "id": "test-product", + "is_giftcard": false, + "length": null, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "profile_id": Any, + "status": "draft", + "subtitle": null, + "thumbnail": null, + "title": "Awesome Metal Ball", + "type_id": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "product_id": "test-product", + "sku": null, + "title": "Practical Granite Pizza", + "upc": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "variant_id": "test-variant", + }, + ], + "metadata": null, + "no_notification": null, + "object": "order", + "payment_status": "captured", + "refunds": Array [], + "region": Object { + "automatic_taxes": true, + "created_at": Any, + "currency_code": "usd", + "deleted_at": null, + "fulfillment_providers": Array [], + "gift_cards_taxable": true, + "id": Any, + "metadata": null, + "name": "Test region", + "payment_providers": Array [ + PaymentProvider { + "id": "test-pay", + "is_installed": true, + }, + ], + "tax_code": null, + "tax_provider_id": null, + "tax_rate": 12.5, + "updated_at": Any, + }, + "region_id": "test-region", + "returns": Array [ + Object { + "claim_order_id": null, + "created_at": Any, + "id": Any, + "idempotency_key": Any, + "items": Array [ + Object { + "is_requested": true, + "item_id": "test-item", + "metadata": null, + "note": null, + "quantity": 1, + "reason_id": null, + "received_quantity": null, + "requested_quantity": 1, + "return_id": Any, + }, + ], + "metadata": null, + "no_notification": null, + "order_id": Any, + "received_at": null, + "refund_amount": 1200, + "shipping_data": null, + "status": "requested", + "swap_id": null, + "updated_at": Any, + }, + ], + "shipping_address": Object { + "address_1": "84185 Lindsey Centers", + "address_2": null, + "city": null, + "company": null, + "country_code": "us", + "created_at": Any, + "customer_id": null, + "deleted_at": null, + "first_name": "Chyna", + "id": Any, + "last_name": "Osinski", + "metadata": null, + "phone": null, + "postal_code": "51510", + "province": null, + "updated_at": Any, + }, + "shipping_address_id": Any, + "shipping_methods": Array [], + "status": "pending", + "swaps": Array [], + "tax_rate": null, + "total": 2400, + "updated_at": Any, + }, + "refund_amount": "12.00 USD", + "return_request": Object { + "claim_order_id": null, + "created_at": Any, + "id": Any, + "idempotency_key": Any, + "items": Array [ + Object { + "is_requested": true, + "item": Object { + "allow_discounts": true, + "cart_id": null, + "claim_order_id": null, + "created_at": Any, + "description": "", + "fulfilled_quantity": 2, + "has_shipping": null, + "id": Any, + "is_giftcard": false, + "is_return": false, + "metadata": null, + "order_id": Any, + "quantity": 2, + "returned_quantity": null, + "shipped_quantity": 2, + "should_merge": true, + "swap_id": null, + "tax_lines": Array [ + Object { + "code": "default", + "created_at": Any, + "id": Any, + "item_id": "test-item", + "metadata": null, + "name": "default", + "rate": 20, + "updated_at": Any, + }, + ], + "thumbnail": "", + "title": "Intelligent Plastic Chips", + "unit_price": 1000, + "updated_at": Any, + "variant": Object { + "allow_backorder": false, + "barcode": null, + "created_at": Any, + "deleted_at": null, + "ean": null, + "height": null, + "hs_code": null, + "id": "test-variant", + "inventory_quantity": 10, + "length": null, + "manage_inventory": true, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "product": Object { + "collection_id": null, + "created_at": Any, + "deleted_at": null, + "description": null, + "discountable": true, + "external_id": null, + "handle": null, + "height": null, + "hs_code": null, + "id": "test-product", + "is_giftcard": false, + "length": null, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "profile_id": Any, + "status": "draft", + "subtitle": null, + "thumbnail": null, + "title": "Awesome Metal Ball", + "type_id": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "product_id": "test-product", + "sku": null, + "title": "Practical Granite Pizza", + "upc": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "variant_id": "test-variant", + }, + "item_id": "test-item", + "metadata": null, + "note": null, + "quantity": 1, + "reason_id": null, + "received_quantity": null, + "requested_quantity": 1, + "return_id": Any, + }, + ], + "metadata": null, + "no_notification": null, + "order_id": Any, + "received_at": null, + "refund_amount": "12.00 USD", + "shipping_data": null, + "shipping_method": null, + "status": "requested", + "swap_id": null, + "updated_at": Any, + }, + "shipping_total": "0.00 USD", + "subtotal": "12.00 USD", +} +`; + +exports[`medusa-plugin-sendgrid swap created data 1`] = `"12.00 USD"`; + +exports[`medusa-plugin-sendgrid swap created data 2`] = `"12.00 USD"`; + +exports[`medusa-plugin-sendgrid swap created data 3`] = `"11.25 USD"`; + +exports[`medusa-plugin-sendgrid swap received data 1`] = `"12.00 USD"`; + +exports[`medusa-plugin-sendgrid swap received data 2`] = `"12.00 USD"`; + +exports[`medusa-plugin-sendgrid swap received data 3`] = `"11.25 USD"`; + +exports[`medusa-plugin-sendgrid swap shipment created data 1`] = ` +Object { + "additional_total": "16.88 USD", + "date": Any, + "email": "test@testson.com", + "fulfillment": Object { + "canceled_at": null, + "claim_order_id": null, + "created_at": Any, + "data": Object {}, + "id": Any, + "idempotency_key": null, + "items": Array [ + Object { + "fulfillment_id": Any, + "item_id": Any, + "quantity": 1, + }, + ], + "metadata": Object {}, + "no_notification": null, + "order_id": null, + "provider_id": "test-ful", + "shipped_at": Any, + "swap_id": Any, + "tracking_links": Array [], + "tracking_numbers": Array [], + "updated_at": Any, + }, + "items": Array [ + Object { + "allow_discounts": true, + "cart_id": Any, + "claim_order_id": null, + "created_at": Any, + "description": "Small Wooden Computer", + "discounted_price": "11.25 USD", + "fulfilled_quantity": 1, + "has_shipping": true, + "id": Any, + "is_giftcard": false, + "is_return": false, + "metadata": Object {}, + "order_id": null, + "price": "11.25 USD", + "quantity": 1, + "returned_quantity": null, + "shipped_quantity": 1, + "should_merge": true, + "swap_id": Any, + "tax_lines": Array [ + Object { + "code": "default", + "created_at": Any, + "id": Any, + "item_id": Any, + "metadata": null, + "name": "default", + "rate": 12.5, + "updated_at": Any, + }, + ], + "thumbnail": null, + "title": "Awesome Metal Ball", + "unit_price": 1000, + "updated_at": Any, + "variant": Object { + "allow_backorder": false, + "barcode": null, + "created_at": Any, + "deleted_at": null, + "ean": null, + "height": null, + "hs_code": null, + "id": "variant-2", + "inventory_quantity": 9, + "length": null, + "manage_inventory": true, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "product": Object { + "collection_id": null, + "created_at": Any, + "deleted_at": null, + "description": null, + "discountable": true, + "external_id": null, + "handle": null, + "height": null, + "hs_code": null, + "id": "test-product", + "is_giftcard": false, + "length": null, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "profile_id": Any, + "status": "draft", + "subtitle": null, + "thumbnail": null, + "title": "Awesome Metal Ball", + "type_id": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "product_id": "test-product", + "sku": null, + "title": "Small Wooden Computer", + "upc": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "variant_id": "variant-2", + }, + ], + "locale": null, + "order": Object { + "beforeInsert": [Function], + "billing_address_id": null, + "canceled_at": null, + "cart_id": null, + "created_at": Any, + "currency_code": "usd", + "customer_id": Any, + "discounts": Array [], + "display_id": Any, + "draft_order_id": null, + "email": "test@testson.com", + "external_id": null, + "fulfillment_status": "fulfilled", + "id": Any, + "idempotency_key": null, + "items": Array [ + Object { + "allow_discounts": true, + "cart_id": null, + "claim_order_id": null, + "created_at": Any, + "description": "", + "fulfilled_quantity": 2, + "has_shipping": null, + "id": Any, + "is_giftcard": false, + "is_return": false, + "metadata": null, + "order_id": Any, + "quantity": 2, + "returned_quantity": null, + "shipped_quantity": 2, + "should_merge": true, + "swap_id": null, + "tax_lines": Array [ + Object { + "code": "default", + "created_at": Any, + "id": Any, + "item_id": Any, + "metadata": null, + "name": "default", + "rate": 20, + "updated_at": Any, + }, + ], + "thumbnail": "", + "title": "Intelligent Plastic Chips", + "unit_price": 1000, + "updated_at": Any, + "variant": Object { + "allow_backorder": false, + "barcode": null, + "created_at": Any, + "deleted_at": null, + "ean": null, + "height": null, + "hs_code": null, + "id": "test-variant", + "inventory_quantity": 9, + "length": null, + "manage_inventory": true, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "product": Object { + "collection_id": null, + "created_at": Any, + "deleted_at": null, + "description": null, + "discountable": true, + "external_id": null, + "handle": null, + "height": null, + "hs_code": null, + "id": "test-product", + "is_giftcard": false, + "length": null, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "profile_id": Any, + "status": "draft", + "subtitle": null, + "thumbnail": null, + "title": "Awesome Metal Ball", + "type_id": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "product_id": "test-product", + "sku": null, + "title": "Practical Granite Pizza", + "upc": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "variant_id": "test-variant", + }, + ], + "metadata": null, + "no_notification": null, + "object": "order", + "payment_status": "captured", + "region": Object { + "automatic_taxes": true, + "created_at": Any, + "currency_code": "usd", + "deleted_at": null, + "fulfillment_providers": Array [], + "gift_cards_taxable": true, + "id": Any, + "metadata": null, + "name": "Test region", + "payment_providers": Array [ + PaymentProvider { + "id": "test-pay", + "is_installed": true, + }, + ], + "tax_code": null, + "tax_provider_id": null, + "tax_rate": 12.5, + "updated_at": Any, + }, + "region_id": "test-region", + "shipping_address_id": Any, + "status": "pending", + "swaps": Array [ + Object { + "additional_items": Array [ + Object { + "allow_discounts": true, + "cart_id": Any, + "claim_order_id": null, + "created_at": Any, + "description": "Small Wooden Computer", + "fulfilled_quantity": 1, + "has_shipping": true, + "id": Any, + "is_giftcard": false, + "is_return": false, + "metadata": Object {}, + "order_id": null, + "quantity": 1, + "returned_quantity": null, + "shipped_quantity": 1, + "should_merge": true, + "swap_id": Any, + "tax_lines": Array [ + Object { + "code": "default", + "created_at": Any, + "id": Any, + "item_id": Any, + "metadata": null, + "name": "default", + "rate": 12.5, + "updated_at": Any, + }, + ], + "thumbnail": null, + "title": "Awesome Metal Ball", + "unit_price": 1000, + "updated_at": Any, + "variant": Object { + "allow_backorder": false, + "barcode": null, + "created_at": Any, + "deleted_at": null, + "ean": null, + "height": null, + "hs_code": null, + "id": "variant-2", + "inventory_quantity": 9, + "length": null, + "manage_inventory": true, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "product": Object { + "collection_id": null, + "created_at": Any, + "deleted_at": null, + "description": null, + "discountable": true, + "external_id": null, + "handle": null, + "height": null, + "hs_code": null, + "id": "test-product", + "is_giftcard": false, + "length": null, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "profile_id": Any, + "status": "draft", + "subtitle": null, + "thumbnail": null, + "title": "Awesome Metal Ball", + "type_id": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "product_id": "test-product", + "sku": null, + "title": "Small Wooden Computer", + "upc": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "variant_id": "variant-2", + }, + ], + "allow_backorder": true, + "canceled_at": null, + "cart_id": Any, + "confirmed_at": Any, + "created_at": Any, + "deleted_at": null, + "difference_due": 488, + "fulfillment_status": "shipped", + "id": Any, + "idempotency_key": Any, + "metadata": null, + "no_notification": null, + "order_id": Any, + "payment_status": "awaiting", + "shipping_address_id": Any, + "updated_at": Any, + }, + ], + "tax_rate": null, + "updated_at": Any, + }, + "paid_total": "4.88 USD", + "refund_amount": "12.00 USD", + "return_total": "12.00 USD", + "swap": Object { + "additional_items": Array [ + Object { + "allow_discounts": true, + "cart_id": Any, + "claim_order_id": null, + "created_at": Any, + "description": "Small Wooden Computer", + "fulfilled_quantity": 1, + "has_shipping": true, + "id": Any, + "is_giftcard": false, + "is_return": false, + "metadata": Object {}, + "order_id": null, + "quantity": 1, + "returned_quantity": null, + "shipped_quantity": 1, + "should_merge": true, + "swap_id": Any, + "tax_lines": Array [ + Object { + "code": "default", + "created_at": Any, + "id": Any, + "item_id": Any, + "metadata": null, + "name": "default", + "rate": 12.5, + "updated_at": Any, + }, + ], + "thumbnail": null, + "title": "Awesome Metal Ball", + "unit_price": 1000, + "updated_at": Any, + "variant": Object { + "allow_backorder": false, + "barcode": null, + "created_at": Any, + "deleted_at": null, + "ean": null, + "height": null, + "hs_code": null, + "id": "variant-2", + "inventory_quantity": 9, + "length": null, + "manage_inventory": true, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "product": Object { + "collection_id": null, + "created_at": Any, + "deleted_at": null, + "description": null, + "discountable": true, + "external_id": null, + "handle": null, + "height": null, + "hs_code": null, + "id": "test-product", + "is_giftcard": false, + "length": null, + "material": null, + "metadata": null, + "mid_code": null, + "origin_country": null, + "profile_id": Any, + "status": "draft", + "subtitle": null, + "thumbnail": null, + "title": "Awesome Metal Ball", + "type_id": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "product_id": "test-product", + "sku": null, + "title": "Small Wooden Computer", + "upc": null, + "updated_at": Any, + "weight": null, + "width": null, + }, + "variant_id": "variant-2", + }, + ], + "allow_backorder": true, + "beforeInsert": [Function], + "canceled_at": null, + "cart_id": Any, + "confirmed_at": Any, + "created_at": Any, + "deleted_at": null, + "difference_due": 488, + "fulfillment_status": "shipped", + "id": Any, + "idempotency_key": Any, + "metadata": null, + "no_notification": null, + "order_id": Any, + "payment_status": "awaiting", + "return_order": Object { + "claim_order_id": null, + "created_at": Any, + "id": Any, + "idempotency_key": null, + "items": Array [ + Object { + "is_requested": true, + "item_id": "test-item", + "metadata": null, + "note": null, + "quantity": 1, + "reason_id": null, + "received_quantity": null, + "requested_quantity": 1, + "return_id": Any, + }, + ], + "metadata": null, + "no_notification": null, + "order_id": null, + "received_at": null, + "refund_amount": 1200, + "shipping_data": null, + "status": "requested", + "swap_id": Any, + "updated_at": Any, + }, + "shipping_address": Object { + "address_1": "121 W Something St", + "address_2": null, + "city": "ville la something", + "company": null, + "country_code": null, + "created_at": Any, + "customer_id": null, + "deleted_at": null, + "first_name": null, + "id": Any, + "last_name": null, + "metadata": null, + "phone": "12353245", + "postal_code": "1234", + "province": "something", + "updated_at": Any, + }, + "shipping_address_id": Any, + "shipping_methods": Array [ + Object { + "cart_id": Any, + "claim_order_id": null, + "data": Object {}, + "id": Any, + "order_id": null, + "price": 500, + "return_id": null, + "shipping_option": Object { + "admin_only": false, + "amount": 500, + "created_at": Any, + "data": Object {}, + "deleted_at": null, + "id": Any, + "is_return": false, + "metadata": null, + "name": "Test Method", + "price_type": "flat_rate", + "profile_id": Any, + "provider_id": "test-ful", + "region_id": "test-region", + "updated_at": Any, + }, + "shipping_option_id": Any, + "swap_id": Any, + "tax_lines": Array [ + Object { + "code": "default", + "created_at": Any, + "id": Any, + "metadata": null, + "name": "default", + "rate": 12.5, + "shipping_method_id": Any, + "updated_at": Any, + }, + ], + }, + ], + "updated_at": Any, + }, + "tax_amount": "-0.12 USD", + "tracking_links": Array [], + "tracking_number": "", +} +`; diff --git a/integration-tests/plugins/__tests__/medusa-plugin-sendgrid/index.js b/integration-tests/plugins/__tests__/medusa-plugin-sendgrid/index.js new file mode 100644 index 0000000000..1844ccea57 --- /dev/null +++ b/integration-tests/plugins/__tests__/medusa-plugin-sendgrid/index.js @@ -0,0 +1,911 @@ +const path = require("path") + +const { bootstrapApp } = require("../../../helpers/bootstrap-app") +const { initDb, useDb } = require("../../../helpers/use-db") +const { setPort, useApi } = require("../../../helpers/use-api") + +const adminSeeder = require("../../helpers/admin-seeder") + +const { + simpleOrderFactory, + simpleStoreFactory, + simpleProductFactory, + simpleShippingOptionFactory, +} = require("../../factories") + +describe("medusa-plugin-sendgrid", () => { + let appContainer + let dbConnection + let express + + const doAfterEach = async () => { + const db = useDb() + return await db.teardown() + } + + beforeAll(async () => { + const cwd = path.resolve(path.join(__dirname, "..", "..")) + try { + dbConnection = await initDb({ cwd }) + const { container, app, port } = await bootstrapApp({ cwd }) + appContainer = container + + setPort(port) + express = app.listen(port, (err) => { + process.send(port) + }) + } catch (error) { + console.log(error) + throw error + } + }) + + afterAll(async () => { + const db = useDb() + await db.shutdown() + express.close() + // medusaProcess.kill() + }) + + afterEach(async () => { + return await doAfterEach() + }) + + test("order canceled data", async () => { + await adminSeeder(dbConnection) + + const order = await createReturnableOrder(dbConnection, { + notShipped: true, + }) + const api = useApi() + + const response = await api.post( + `/admin/orders/${order.id}/cancel`, + {}, + { headers: { authorization: "Bearer test_token" } } + ) + expect(response.status).toEqual(200) + + const sendgridService = appContainer.resolve("sendgridService") + const data = await sendgridService.fetchData("order.canceled", { + id: order.id, + }) + + expect(data).toMatchSnapshot({ + date: expect.any(String), + id: expect.any(String), + display_id: expect.any(Number), + created_at: expect.any(Date), + canceled_at: expect.any(Date), + updated_at: expect.any(Date), + customer_id: expect.any(String), + customer: { + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + shipping_methods: [ + { + id: expect.any(String), + shipping_option_id: expect.any(String), + order_id: expect.any(String), + shipping_option: { + id: expect.any(String), + profile_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + }, + ], + shipping_address_id: expect.any(String), + shipping_address: { + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + items: [ + { + created_at: expect.any(Date), + updated_at: expect.any(Date), + order_id: expect.any(String), + tax_lines: [ + { + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + ], + variant: { + created_at: expect.any(Date), + updated_at: expect.any(Date), + product: { + profile_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + }, + }, + ], + region: { + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + }) + }) + + test("order shipment created data", async () => { + await adminSeeder(dbConnection) + + const order = await createReturnableOrder(dbConnection, { + notShipped: true, + }) + const api = useApi() + + const { data: fulfillmentData } = await api.post( + `/admin/orders/${order.id}/fulfillment`, + { items: [{ item_id: "test-item", quantity: 2 }] }, + { headers: { authorization: "Bearer test_token" } } + ) + + const fulfillment = fulfillmentData.order.fulfillments[0] + + const response = await api.post( + `/admin/orders/${order.id}/shipment`, + { fulfillment_id: fulfillment.id }, + { headers: { authorization: "Bearer test_token" } } + ) + + expect(response.status).toEqual(200) + + const sendgridService = appContainer.resolve("sendgridService") + const data = await sendgridService.fetchData("order.shipment_created", { + id: order.id, + fulfillment_id: fulfillment.id, + }) + + expect(data).toMatchSnapshot({ + date: expect.any(String), + fulfillment: { + id: expect.any(String), + order_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + shipped_at: expect.any(Date), + items: [ + { + fulfillment_id: expect.any(String), + }, + ], + }, + order: { + display_id: expect.any(Number), + id: expect.any(String), + display_id: expect.any(Number), + created_at: expect.any(Date), + updated_at: expect.any(Date), + customer_id: expect.any(String), + customer: { + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + + fulfillments: [ + { + id: expect.any(String), + order_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + shipped_at: expect.any(Date), + items: [ + { + fulfillment_id: expect.any(String), + }, + ], + }, + ], + shipping_methods: [ + { + id: expect.any(String), + shipping_option_id: expect.any(String), + order_id: expect.any(String), + shipping_option: { + id: expect.any(String), + profile_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + }, + ], + shipping_address_id: expect.any(String), + shipping_address: { + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + items: [ + { + created_at: expect.any(Date), + updated_at: expect.any(Date), + order_id: expect.any(String), + tax_lines: [ + { + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + ], + variant: { + created_at: expect.any(Date), + updated_at: expect.any(Date), + product: { + profile_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + }, + }, + ], + region: { + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + }, + }) + }) + + test("order placed data", async () => { + await adminSeeder(dbConnection) + + const order = await createReturnableOrder(dbConnection) + const sendgridService = appContainer.resolve("sendgridService") + const data = await sendgridService.fetchData("order.placed", { + id: order.id, + }) + + expect(data).toMatchSnapshot({ + date: expect.any(String), + id: expect.any(String), + display_id: expect.any(Number), + created_at: expect.any(Date), + updated_at: expect.any(Date), + customer_id: expect.any(String), + customer: { + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + shipping_address_id: expect.any(String), + shipping_address: { + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + items: [ + { + created_at: expect.any(Date), + updated_at: expect.any(Date), + order_id: expect.any(String), + tax_lines: [ + { + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + ], + variant: { + created_at: expect.any(Date), + updated_at: expect.any(Date), + product: { + profile_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + }, + totals: { + tax_lines: [ + { + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + ], + }, + }, + ], + region: { + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + }) + }) + + test("swap received data", async () => { + await simpleStoreFactory(dbConnection) + await adminSeeder(dbConnection) + + const order = await createReturnableOrder(dbConnection) + const api = useApi() + + const response = await api.post( + `/admin/orders/${order.id}/swaps`, + { + additional_items: [{ variant_id: "variant-2", quantity: 1 }], + return_items: [{ item_id: "test-item", quantity: 1 }], + }, + { headers: { authorization: "Bearer test_token" } } + ) + + expect(response.status).toEqual(200) + + expect(response.status).toEqual(200) + + const swap = response.data.order.swaps[0] + const returnOrder = swap.return_order + await api.post( + `/admin/returns/${returnOrder.id}/receive`, + { + items: returnOrder.items.map((i) => ({ + item_id: i.item_id, + quantity: i.quantity, + })), + }, + { headers: { authorization: "Bearer test_token" } } + ) + + const sendgridService = appContainer.resolve("sendgridService") + const data = await sendgridService.fetchData("swap.received", { + id: swap.id, + order_id: order.id, + }) + + expect(data.return_total).toMatchSnapshot() + expect(data.refund_amount).toMatchSnapshot() + expect(data.additional_total).toMatchSnapshot() + }) + + test("items returned data", async () => { + await adminSeeder(dbConnection) + + const order = await createReturnableOrder(dbConnection) + const api = useApi() + + const response = await api.post( + `/admin/orders/${order.id}/return`, + { + items: [{ item_id: "test-item", quantity: 1 }], + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + + const returnOrder = response.data.order.returns[0] + const returnId = returnOrder.id + await api.post( + `/admin/returns/${returnId}/receive`, + { + items: returnOrder.items.map((i) => ({ + item_id: i.item_id, + quantity: i.quantity, + })), + }, + { headers: { authorization: "Bearer test_token" } } + ) + + const sendgridService = appContainer.resolve("sendgridService") + const data = await sendgridService.fetchData("order.items_returned", { + id: order.id, + return_id: returnId, + }) + + const returnSnap = getReturnSnap(true) + expect(data).toMatchSnapshot(returnSnap) + }) + + test("claim shipment created data", async () => { + await adminSeeder(dbConnection) + + const order = await createReturnableOrder(dbConnection) + const shippingOut = await simpleShippingOptionFactory(dbConnection, { + region_id: "test-region", + price: 500, + }) + const api = useApi() + + const response = await api.post( + `/admin/orders/${order.id}/claims`, + { + type: "replace", + additional_items: [{ variant_id: "variant-2", quantity: 1 }], + shipping_methods: [ + { + option_id: shippingOut.id, + price: 0, + }, + ], + claim_items: [ + { reason: "missing_item", item_id: "test-item", quantity: 1 }, + ], + }, + { headers: { authorization: "Bearer test_token" } } + ) + + expect(response.status).toEqual(200) + + const claimId = response.data.order.claims[0].id + + const { data: fulfillmentData } = await api.post( + `/admin/orders/${order.id}/claims/${claimId}/fulfillments`, + {}, + { headers: { authorization: "Bearer test_token" } } + ) + + const fulfillmentId = fulfillmentData.order.claims[0].fulfillments[0].id + await api.post( + `/admin/orders/${order.id}/claims/${claimId}/shipments`, + { fulfillment_id: fulfillmentId }, + { headers: { authorization: "Bearer test_token" } } + ) + + const sendgridService = appContainer.resolve("sendgridService") + const data = await sendgridService.fetchData("claim.shipment_created", { + id: claimId, + fulfillment_id: fulfillmentId, + }) + + const orderSnap = { + id: expect.any(String), + display_id: expect.any(Number), + customer_id: expect.any(String), + shipping_address_id: expect.any(String), + shipping_address: { + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + created_at: expect.any(Date), + updated_at: expect.any(Date), + items: [ + { + id: expect.any(String), + order_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + variant: { + created_at: expect.any(Date), + updated_at: expect.any(Date), + product: { + profile_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + }, + }, + ], + } + + expect(data).toMatchSnapshot({ + claim: { + id: expect.any(String), + order_id: expect.any(String), + shipping_address_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + idempotency_key: expect.any(String), + order: orderSnap, + }, + fulfillment: { + id: expect.any(String), + claim_order_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + shipped_at: expect.any(Date), + items: [ + { + fulfillment_id: expect.any(String), + item_id: expect.any(String), + }, + ], + }, + order: orderSnap, + }) + }) + + test("swap shipment created data", async () => { + await simpleStoreFactory(dbConnection) + await adminSeeder(dbConnection) + + const order = await createReturnableOrder(dbConnection) + const shippingOut = await simpleShippingOptionFactory(dbConnection, { + region_id: "test-region", + price: 500, + }) + const api = useApi() + + const response = await api.post( + `/admin/orders/${order.id}/swaps`, + { + additional_items: [{ variant_id: "variant-2", quantity: 1 }], + return_items: [{ item_id: "test-item", quantity: 1 }], + }, + { headers: { authorization: "Bearer test_token" } } + ) + + expect(response.status).toEqual(200) + + const swapId = response.data.order.swaps[0].id + const cartId = response.data.order.swaps[0].cart_id + + await api.post(`/store/carts/${cartId}`, { + shipping_address: { + address_1: "121 W Something St", + postal_code: "1234", + province: "something", + city: "ville la something", + phone: "12353245", + }, + }) + await api.post(`/store/carts/${cartId}/shipping-methods`, { + option_id: shippingOut.id, + }) + await api.post(`/store/carts/${cartId}/payment-sessions`) + await api.post(`/store/carts/${cartId}/complete`) + const { data: fulfillmentData } = await api.post( + `/admin/orders/${order.id}/swaps/${swapId}/fulfillments`, + {}, + { headers: { authorization: "Bearer test_token" } } + ) + + const fulfillmentId = fulfillmentData.order.swaps[0].fulfillments[0].id + await api.post( + `/admin/orders/${order.id}/swaps/${swapId}/shipments`, + { fulfillment_id: fulfillmentId }, + { headers: { authorization: "Bearer test_token" } } + ) + + const sendgridService = appContainer.resolve("sendgridService") + const data = await sendgridService.fetchData("swap.shipment_created", { + id: swapId, + fulfillment_id: fulfillmentId, + }) + + const itemSnap = { + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + variant: { + created_at: expect.any(Date), + updated_at: expect.any(Date), + product: { + profile_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + }, + tax_lines: [ + { + id: expect.any(String), + item_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + ], + } + + const swapSnap = { + id: expect.any(String), + cart_id: expect.any(String), + order_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + confirmed_at: expect.any(Date), + idempotency_key: expect.any(String), + shipping_address_id: expect.any(String), + additional_items: [ + { + swap_id: expect.any(String), + cart_id: expect.any(String), + ...itemSnap, + }, + ], + } + + expect(data).toMatchSnapshot({ + date: expect.any(String), + swap: { + ...swapSnap, + shipping_address: { + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + shipping_methods: [ + { + id: expect.any(String), + cart_id: expect.any(String), + swap_id: expect.any(String), + shipping_option: { + id: expect.any(String), + profile_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + shipping_option_id: expect.any(String), + tax_lines: [ + { + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + shipping_method_id: expect.any(String), + }, + ], + }, + ], + return_order: { + id: expect.any(String), + swap_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + items: [ + { + return_id: expect.any(String), + }, + ], + }, + }, + fulfillment: { + id: expect.any(String), + created_at: expect.any(Date), + shipped_at: expect.any(Date), + updated_at: expect.any(Date), + swap_id: expect.any(String), + items: [ + { + fulfillment_id: expect.any(String), + item_id: expect.any(String), + }, + ], + }, + order: { + display_id: expect.any(Number), + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + items: [{ order_id: expect.any(String), ...itemSnap }], + customer_id: expect.any(String), + shipping_address_id: expect.any(String), + swaps: [swapSnap], + region: { + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + }, + items: [ + { + swap_id: expect.any(String), + cart_id: expect.any(String), + ...itemSnap, + }, + ], + }) + }) + + test("return requested data", async () => { + await adminSeeder(dbConnection) + + const order = await createReturnableOrder(dbConnection) + const api = useApi() + + const response = await api.post( + `/admin/orders/${order.id}/return`, + { + items: [{ item_id: "test-item", quantity: 1 }], + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + + const sendgridService = appContainer.resolve("sendgridService") + const data = await sendgridService.fetchData("order.return_requested", { + id: response.data.order.id, + return_id: response.data.order.returns[0].id, + }) + const returnSnap = getReturnSnap() + expect(data).toMatchSnapshot(returnSnap) + }) + + test("swap created data", async () => { + await adminSeeder(dbConnection) + + const order = await createReturnableOrder(dbConnection) + const api = useApi() + + const response = await api.post( + `/admin/orders/${order.id}/swaps`, + { + additional_items: [{ variant_id: "variant-2", quantity: 1 }], + return_items: [{ item_id: "test-item", quantity: 1 }], + }, + { + headers: { + authorization: "Bearer test_token", + }, + } + ) + + expect(response.status).toEqual(200) + + const sendgridService = appContainer.resolve("sendgridService") + const data = await sendgridService.fetchData("swap.created", { + id: response.data.order.swaps[0].id, + }) + + expect(data.return_total).toMatchSnapshot() + expect(data.refund_amount).toMatchSnapshot() + expect(data.additional_total).toMatchSnapshot() + }) +}) + +const getReturnSnap = (received = false) => { + const itemSnap = { + id: expect.any(String), + order_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + variant: { + created_at: expect.any(Date), + updated_at: expect.any(Date), + product: { + profile_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + }, + tax_lines: [ + { + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + ], + } + + return { + date: expect.any(String), + order: { + display_id: expect.any(Number), + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + items: [itemSnap], + customer_id: expect.any(String), + shipping_address_id: expect.any(String), + returns: [ + { + id: expect.any(String), + received_at: received ? expect.any(Date) : null, + order_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + idempotency_key: expect.any(String), + items: [ + { + return_id: expect.any(String), + }, + ], + }, + ], + shipping_address: { + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + region: { + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + }, + return_request: { + id: expect.any(String), + received_at: received ? expect.any(Date) : null, + order_id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + idempotency_key: expect.any(String), + items: [ + { + return_id: expect.any(String), + item: itemSnap, + }, + ], + }, + items: [ + { + ...itemSnap, + totals: { + tax_lines: [ + { + id: expect.any(String), + created_at: expect.any(Date), + updated_at: expect.any(Date), + }, + ], + }, + }, + ], + } +} + +const createReturnableOrder = async (dbConnection, options = {}) => { + await simpleProductFactory( + dbConnection, + { + id: "test-product", + variants: [ + { id: "test-variant" }, + { id: "variant-2", prices: [{ currency: "usd", amount: 1000 }] }, + ], + }, + 100 + ) + + let discounts = [] + + if (options.discount) { + discounts = [ + { + code: "TESTCODE", + }, + ] + } + + return await simpleOrderFactory(dbConnection, { + email: "test@testson.com", + tax_rate: null, + fulfillment_status: "fulfilled", + payment_status: "captured", + shipping_methods: options.notShipped + ? [ + { + price: 0, + shipping_option: { name: "free", region_id: "test-region" }, + }, + ] + : [], + region: { + id: "test-region", + name: "Test region", + tax_rate: 12.5, // Should be ignored due to item tax line + }, + discounts, + line_items: [ + { + id: "test-item", + variant_id: "test-variant", + quantity: 2, + fulfilled_quantity: options.notShipped ? 0 : 2, + shipped_quantity: options.notShipped ? 0 : 2, + unit_price: 1000, + tax_lines: [ + { + name: "default", + code: "default", + rate: 20, + }, + ], + }, + ], + }) +} diff --git a/integration-tests/plugins/factories/index.ts b/integration-tests/plugins/factories/index.ts new file mode 100644 index 0000000000..2830eed241 --- /dev/null +++ b/integration-tests/plugins/factories/index.ts @@ -0,0 +1,13 @@ +export * from "./simple-order-factory" +export * from "./simple-cart-factory" +export * from "./simple-region-factory" +export * from "./simple-line-item-factory" +export * from "./simple-product-factory" +export * from "./simple-product-variant-factory" +export * from "./simple-product-tax-rate-factory" +export * from "./simple-shipping-tax-rate-factory" +export * from "./simple-tax-rate-factory" +export * from "./simple-shipping-option-factory" +export * from "./simple-shipping-method-factory" +export * from "./simple-product-type-tax-rate-factory" +export * from "./simple-store-factory" diff --git a/integration-tests/plugins/factories/simple-address-factory.ts b/integration-tests/plugins/factories/simple-address-factory.ts new file mode 100644 index 0000000000..cb40d162d8 --- /dev/null +++ b/integration-tests/plugins/factories/simple-address-factory.ts @@ -0,0 +1,34 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { Address } from "@medusajs/medusa" + +export type AddressFactoryData = { + first_name?: string + last_name?: string + country_code?: string + address_1?: string + postal_code?: string +} + +export const simpleAddressFactory = async ( + connection: Connection, + data: AddressFactoryData = {}, + seed?: number +): Promise
=> { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + const address = manager.create(Address, { + id: `simple-id-${Math.random() * 1000}`, + first_name: data.first_name || faker.name.firstName(), + last_name: data.last_name || faker.name.lastName(), + country_code: data.country_code || "us", + address_1: data.address_1 || faker.address.streetAddress(), + postal_code: data.postal_code || faker.address.zipCode(), + }) + + return await manager.save(address) +} diff --git a/integration-tests/plugins/factories/simple-cart-factory.ts b/integration-tests/plugins/factories/simple-cart-factory.ts new file mode 100644 index 0000000000..33a10cff75 --- /dev/null +++ b/integration-tests/plugins/factories/simple-cart-factory.ts @@ -0,0 +1,70 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { Cart } from "@medusajs/medusa" + +import { RegionFactoryData, simpleRegionFactory } from "./simple-region-factory" +import { + LineItemFactoryData, + simpleLineItemFactory, +} from "./simple-line-item-factory" +import { + AddressFactoryData, + simpleAddressFactory, +} from "./simple-address-factory" +import { + ShippingMethodFactoryData, + simpleShippingMethodFactory, +} from "./simple-shipping-method-factory" + +export type CartFactoryData = { + id?: string + region?: RegionFactoryData | string + email?: string | null + line_items?: LineItemFactoryData[] + shipping_address?: AddressFactoryData + shipping_methods?: ShippingMethodFactoryData[] +} + +export const simpleCartFactory = async ( + connection: Connection, + data: CartFactoryData = {}, + seed: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + let regionId: string + if (typeof data.region === "string") { + regionId = data.region + } else { + const region = await simpleRegionFactory(connection, data.region) + regionId = region.id + } + const address = await simpleAddressFactory(connection, data.shipping_address) + + const id = data.id || `simple-cart-${Math.random() * 1000}` + const toSave = manager.create(Cart, { + id, + email: + typeof data.email !== "undefined" ? data.email : faker.internet.email(), + region_id: regionId, + shipping_address_id: address.id, + }) + + const cart = await manager.save(toSave) + + const shippingMethods = data.shipping_methods || [] + for (const sm of shippingMethods) { + await simpleShippingMethodFactory(connection, { ...sm, cart_id: id }) + } + + const items = data.line_items + for (const item of items) { + await simpleLineItemFactory(connection, { ...item, cart_id: id }) + } + + return cart +} diff --git a/integration-tests/plugins/factories/simple-discount-factory.ts b/integration-tests/plugins/factories/simple-discount-factory.ts new file mode 100644 index 0000000000..8fbb13cd28 --- /dev/null +++ b/integration-tests/plugins/factories/simple-discount-factory.ts @@ -0,0 +1,55 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { + Discount, + DiscountRule, + DiscountRuleType, + AllocationType, +} from "@medusajs/medusa" + +export type DiscountRuleFactoryData = { + type?: DiscountRuleType + value?: number + allocation?: AllocationType +} + +export type DiscountFactoryData = { + id?: string + code?: string + is_dynamic?: boolean + rule?: DiscountRuleFactoryData + regions?: string[] +} + +export const simpleDiscountFactory = async ( + connection: Connection, + data: DiscountFactoryData = {}, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + const ruleData = data.rule ?? {} + const ruleToSave = manager.create(DiscountRule, { + type: ruleData.type ?? DiscountRuleType.PERCENTAGE, + value: ruleData.value ?? 10, + allocation: ruleData.allocation ?? AllocationType.TOTAL, + }) + + const dRule = await manager.save(ruleToSave) + + const toSave = manager.create(Discount, { + id: data.id, + is_dynamic: data.is_dynamic ?? false, + is_disabled: false, + rule_id: dRule.id, + code: data.code ?? "TESTCODE", + regions: data.regions?.map((r) => ({ id: r })) || [], + }) + + const discount = await manager.save(toSave) + return discount +} diff --git a/integration-tests/plugins/factories/simple-line-item-factory.ts b/integration-tests/plugins/factories/simple-line-item-factory.ts new file mode 100644 index 0000000000..84995c79f3 --- /dev/null +++ b/integration-tests/plugins/factories/simple-line-item-factory.ts @@ -0,0 +1,84 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { LineItem, LineItemTaxLine } from "@medusajs/medusa" + +type TaxLineFactoryData = { + rate: number + code: string + name: string +} + +export type LineItemFactoryData = { + id?: string + cart_id?: string + order_id?: string + variant_id: string | null + title?: string + description?: string + thumbnail?: string + should_merge?: boolean + allow_discounts?: boolean + unit_price?: number + quantity?: number + fulfilled_quantity?: boolean + shipped_quantity?: boolean + returned_quantity?: boolean + tax_lines?: TaxLineFactoryData[] +} + +export const simpleLineItemFactory = async ( + connection: Connection, + data: LineItemFactoryData, + seed?: number +): Promise => { + if ( + typeof data.cart_id === "undefined" && + typeof data.order_id === "undefined" + ) { + throw Error() + } + + if (typeof seed !== "undefined") { + faker.seed(seed) + Math + } + + const manager = connection.manager + + const id = data.id || `simple-line-${Math.random() * 1000}` + const toSave = manager.create(LineItem, { + id, + cart_id: data.cart_id, + order_id: data.order_id, + title: data.title || faker.commerce.productName(), + description: data.description || "", + thumbnail: data.thumbnail || "", + should_merge: + typeof data.should_merge !== "undefined" ? data.should_merge : true, + allow_discounts: + typeof data.allow_discounts !== "undefined" ? data.allow_discounts : true, + unit_price: typeof data.unit_price !== "undefined" ? data.unit_price : 100, + variant_id: data.variant_id, + quantity: data.quantity || 1, + fulfilled_quantity: data.fulfilled_quantity || null, + shipped_quantity: data.shipped_quantity || null, + returned_quantity: data.returned_quantity || null, + }) + + const line = await manager.save(toSave) + + if (typeof data.tax_lines !== "undefined") { + const taxLinesToSave = data.tax_lines.map((tl) => + manager.create(LineItemTaxLine, { + item_id: id, + rate: tl.rate, + code: tl.code, + name: tl.name, + }) + ) + + await manager.save(taxLinesToSave) + } + + return line +} diff --git a/integration-tests/plugins/factories/simple-order-factory.ts b/integration-tests/plugins/factories/simple-order-factory.ts new file mode 100644 index 0000000000..4153aa0fe2 --- /dev/null +++ b/integration-tests/plugins/factories/simple-order-factory.ts @@ -0,0 +1,110 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { + Customer, + Order, + PaymentStatus, + FulfillmentStatus, +} from "@medusajs/medusa" + +import { + DiscountFactoryData, + simpleDiscountFactory, +} from "./simple-discount-factory" +import { RegionFactoryData, simpleRegionFactory } from "./simple-region-factory" +import { + LineItemFactoryData, + simpleLineItemFactory, +} from "./simple-line-item-factory" +import { + AddressFactoryData, + simpleAddressFactory, +} from "./simple-address-factory" +import { + ShippingMethodFactoryData, + simpleShippingMethodFactory, +} from "./simple-shipping-method-factory" + +export type OrderFactoryData = { + id?: string + payment_status?: PaymentStatus + fulfillment_status?: FulfillmentStatus + region?: RegionFactoryData | string + email?: string | null + currency_code?: string + tax_rate?: number | null + line_items?: LineItemFactoryData[] + discounts?: DiscountFactoryData[] + shipping_address?: AddressFactoryData + shipping_methods?: ShippingMethodFactoryData[] +} + +export const simpleOrderFactory = async ( + connection: Connection, + data: OrderFactoryData = {}, + seed: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + let currencyCode: string + let regionId: string + let taxRate: number + if (typeof data.region === "string") { + currencyCode = data.currency_code + regionId = data.region + taxRate = data.tax_rate + } else { + const region = await simpleRegionFactory(connection, data.region) + taxRate = + typeof data.tax_rate !== "undefined" ? data.tax_rate : region.tax_rate + currencyCode = region.currency_code + regionId = region.id + } + const address = await simpleAddressFactory(connection, data.shipping_address) + + const customerToSave = manager.create(Customer, { + email: + typeof data.email !== "undefined" ? data.email : faker.internet.email(), + }) + const customer = await manager.save(customerToSave) + + let discounts = [] + if (typeof data.discounts !== "undefined") { + discounts = await Promise.all( + data.discounts.map((d) => simpleDiscountFactory(connection, d, seed)) + ) + } + + const id = data.id || `simple-order-${Math.random() * 1000}` + const toSave = manager.create(Order, { + id, + discounts, + payment_status: data.payment_status ?? PaymentStatus.AWAITING, + fulfillment_status: + data.fulfillment_status ?? FulfillmentStatus.NOT_FULFILLED, + customer_id: customer.id, + email: customer.email, + region_id: regionId, + currency_code: currencyCode, + tax_rate: taxRate, + shipping_address_id: address.id, + }) + + const order = await manager.save(toSave) + + const shippingMethods = data.shipping_methods || [] + for (const sm of shippingMethods) { + await simpleShippingMethodFactory(connection, { ...sm, order_id: order.id }) + } + + const items = data.line_items + for (const item of items) { + await simpleLineItemFactory(connection, { ...item, order_id: id }) + } + + return order +} diff --git a/integration-tests/plugins/factories/simple-product-factory.ts b/integration-tests/plugins/factories/simple-product-factory.ts new file mode 100644 index 0000000000..24746c0f84 --- /dev/null +++ b/integration-tests/plugins/factories/simple-product-factory.ts @@ -0,0 +1,99 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { + ShippingProfileType, + ShippingProfile, + Product, + ProductType, + ProductOption, +} from "@medusajs/medusa" + +import { + simpleProductVariantFactory, + ProductVariantFactoryData, +} from "./simple-product-variant-factory" + +export type ProductFactoryData = { + id?: string + is_giftcard?: boolean + title?: string + type?: string + options?: { id: string; title: string }[] + variants?: ProductVariantFactoryData[] +} + +export const simpleProductFactory = async ( + connection: Connection, + data: ProductFactoryData = {}, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + const defaultProfile = await manager.findOne(ShippingProfile, { + type: ShippingProfileType.DEFAULT, + }) + + const gcProfile = await manager.findOne(ShippingProfile, { + type: ShippingProfileType.GIFT_CARD, + }) + + let typeId: string + if (typeof data.type !== "undefined") { + const toSave = manager.create(ProductType, { + value: data.type, + }) + const res = await manager.save(toSave) + typeId = res.id + } + + const prodId = data.id || `simple-product-${Math.random() * 1000}` + const toSave = manager.create(Product, { + id: prodId, + type_id: typeId, + title: data.title || faker.commerce.productName(), + is_giftcard: data.is_giftcard || false, + discountable: !data.is_giftcard, + profile_id: data.is_giftcard ? gcProfile.id : defaultProfile.id, + }) + + const product = await manager.save(toSave) + + const optionId = `${prodId}-option` + const options = data.options || [{ id: optionId, title: "Size" }] + for (const o of options) { + await manager.insert(ProductOption, { + id: o.id, + title: o.title, + product_id: prodId, + }) + } + + const variants = data.variants || [ + { + id: `simple-test-variant-${Math.random() * 1000}`, + title: "Test", + product_id: prodId, + prices: [{ currency: "usd", amount: 100 }], + options: [{ option_id: optionId, value: "Large" }], + }, + ] + + for (const pv of variants) { + const factoryData = { + ...pv, + product_id: prodId, + } + if (typeof pv.options === "undefined") { + factoryData.options = [ + { option_id: optionId, value: faker.commerce.productAdjective() }, + ] + } + await simpleProductVariantFactory(connection, factoryData) + } + + return product +} diff --git a/integration-tests/plugins/factories/simple-product-tax-rate-factory.ts b/integration-tests/plugins/factories/simple-product-tax-rate-factory.ts new file mode 100644 index 0000000000..4b731c51b3 --- /dev/null +++ b/integration-tests/plugins/factories/simple-product-tax-rate-factory.ts @@ -0,0 +1,48 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { ProductTaxRate, TaxRate } from "@medusajs/medusa" + +type RateFactoryData = { + region_id: string + rate?: number | null + code?: string + name?: string +} + +export type ProductTaxRateFactoryData = { + product_id: string + rate: RateFactoryData | string +} + +export const simpleProductTaxRateFactory = async ( + connection: Connection, + data: ProductTaxRateFactoryData, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + let rateId: string + if (typeof data.rate === "string") { + rateId = data.rate + } else { + const newRate = manager.create(TaxRate, { + region_id: data.rate.region_id, + rate: data.rate.rate, + code: data.rate.code || "sales_tax", + name: data.rate.name || "Sales Tax", + }) + const rate = await manager.save(newRate) + rateId = rate.id + } + + const toSave = manager.create(ProductTaxRate, { + product_id: data.product_id, + rate_id: rateId, + }) + + return await manager.save(toSave) +} diff --git a/integration-tests/plugins/factories/simple-product-type-tax-rate-factory.ts b/integration-tests/plugins/factories/simple-product-type-tax-rate-factory.ts new file mode 100644 index 0000000000..47402a6cbf --- /dev/null +++ b/integration-tests/plugins/factories/simple-product-type-tax-rate-factory.ts @@ -0,0 +1,48 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { ProductTypeTaxRate, TaxRate } from "@medusajs/medusa" + +type RateFactoryData = { + region_id: string + rate?: number | null + code?: string + name?: string +} + +export type ProductTypeTaxRateFactoryData = { + product_type_id: string + rate: RateFactoryData | string +} + +export const simpleProductTypeTaxRateFactory = async ( + connection: Connection, + data: ProductTypeTaxRateFactoryData, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + let rateId: string + if (typeof data.rate === "string") { + rateId = data.rate + } else { + const newRate = manager.create(TaxRate, { + region_id: data.rate.region_id, + rate: data.rate.rate, + code: data.rate.code || "sales_tax", + name: data.rate.name || "Sales Tax", + }) + const rate = await manager.save(newRate) + rateId = rate.id + } + + const toSave = manager.create(ProductTypeTaxRate, { + product_type_id: data.product_type_id, + rate_id: rateId, + }) + + return await manager.save(toSave) +} diff --git a/integration-tests/plugins/factories/simple-product-variant-factory.ts b/integration-tests/plugins/factories/simple-product-variant-factory.ts new file mode 100644 index 0000000000..8d6f6f9cc9 --- /dev/null +++ b/integration-tests/plugins/factories/simple-product-variant-factory.ts @@ -0,0 +1,64 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { + ProductOptionValue, + ProductVariant, + MoneyAmount, +} from "@medusajs/medusa" + +export type ProductVariantFactoryData = { + product_id: string + id?: string + is_giftcard?: boolean + inventory_quantity?: number + title?: string + options?: { option_id: string; value: string }[] + prices?: { currency: string; amount: number }[] +} + +export const simpleProductVariantFactory = async ( + connection: Connection, + data: ProductVariantFactoryData, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + const id = data.id || `simple-variant-${Math.random() * 1000}` + const toSave = manager.create(ProductVariant, { + id, + product_id: data.product_id, + inventory_quantity: + typeof data.inventory_quantity !== "undefined" + ? data.inventory_quantity + : 10, + title: data.title || faker.commerce.productName(), + }) + + const variant = await manager.save(toSave) + + const options = data.options || [{ option_id: "test-option", value: "Large" }] + for (const o of options) { + await manager.insert(ProductOptionValue, { + id: `${o.value}-${o.option_id}`, + value: o.value, + variant_id: id, + option_id: o.option_id, + }) + } + + const prices = data.prices || [{ currency: "usd", amount: 100 }] + for (const p of prices) { + await manager.insert(MoneyAmount, { + id: `${p.currency}-${p.amount}-${Math.random()}`, + variant_id: id, + currency_code: p.currency, + amount: p.amount, + }) + } + + return variant +} diff --git a/integration-tests/plugins/factories/simple-region-factory.ts b/integration-tests/plugins/factories/simple-region-factory.ts new file mode 100644 index 0000000000..0cd08ea702 --- /dev/null +++ b/integration-tests/plugins/factories/simple-region-factory.ts @@ -0,0 +1,47 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { Region } from "@medusajs/medusa" + +export type RegionFactoryData = { + id?: string + name?: string + currency_code?: string + tax_rate?: number + countries?: string[] + automatic_taxes?: boolean +} + +export const simpleRegionFactory = async ( + connection: Connection, + data: RegionFactoryData = {}, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + const regionId = data.id || `simple-region-${Math.random() * 1000}` + const r = manager.create(Region, { + id: regionId, + name: data.name || "Test Region", + currency_code: data.currency_code || "usd", + tax_rate: data.tax_rate || 0, + payment_providers: [{ id: "test-pay" }], + automatic_taxes: + typeof data.automatic_taxes !== "undefined" ? data.automatic_taxes : true, + }) + + const region = await manager.save(r) + + const countries = data.countries || ["us"] + + for (const cc of countries) { + await manager.query( + `UPDATE "country" SET region_id='${regionId}' WHERE iso_2 = '${cc}'` + ) + } + + return region +} diff --git a/integration-tests/plugins/factories/simple-shipping-method-factory.ts b/integration-tests/plugins/factories/simple-shipping-method-factory.ts new file mode 100644 index 0000000000..3fde22e63d --- /dev/null +++ b/integration-tests/plugins/factories/simple-shipping-method-factory.ts @@ -0,0 +1,68 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { ShippingMethodTaxLine, ShippingMethod } from "@medusajs/medusa" + +import { + ShippingOptionFactoryData, + simpleShippingOptionFactory, +} from "./simple-shipping-option-factory" + +export type ShippingMethodFactoryData = { + id?: string + cart_id?: string + order_id?: string + data?: object + price?: number + shipping_option: string | ShippingOptionFactoryData + tax_lines?: ShippingMethodTaxLine[] +} + +export const simpleShippingMethodFactory = async ( + connection: Connection, + data: ShippingMethodFactoryData, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + let shippingOptionId: string + if (typeof data.shipping_option === "string") { + shippingOptionId = data.shipping_option + } else { + const option = await simpleShippingOptionFactory( + connection, + data.shipping_option + ) + shippingOptionId = option.id + } + + const id = data.id || `simple-sm-${Math.random() * 1000}` + const toSave = manager.create(ShippingMethod, { + id, + cart_id: data.cart_id, + order_id: data.order_id, + shipping_option_id: shippingOptionId, + data: data.data || {}, + price: typeof data.price !== "undefined" ? data.price : 500, + }) + + const shippingMethod = await manager.save(toSave) + + if (typeof data.tax_lines !== "undefined") { + const taxLinesToSave = data.tax_lines.map((tl) => + manager.create(ShippingMethodTaxLine, { + shipping_method_id: shippingMethod.id, + rate: tl.rate, + code: tl.code || "default", + name: tl.name || "default", + }) + ) + + await manager.save(taxLinesToSave) + } + + return shippingMethod +} diff --git a/integration-tests/plugins/factories/simple-shipping-option-factory.ts b/integration-tests/plugins/factories/simple-shipping-option-factory.ts new file mode 100644 index 0000000000..4ceed9dd97 --- /dev/null +++ b/integration-tests/plugins/factories/simple-shipping-option-factory.ts @@ -0,0 +1,49 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { + ShippingOptionPriceType, + ShippingProfile, + ShippingOption, + ShippingProfileType, +} from "@medusajs/medusa" + +export type ShippingOptionFactoryData = { + name?: string + region_id: string + is_return?: boolean + is_giftcard?: boolean + price?: number +} + +export const simpleShippingOptionFactory = async ( + connection: Connection, + data: ShippingOptionFactoryData, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + const defaultProfile = await manager.findOne(ShippingProfile, { + type: ShippingProfileType.DEFAULT, + }) + + const gcProfile = await manager.findOne(ShippingProfile, { + type: ShippingProfileType.GIFT_CARD, + }) + + const created = manager.create(ShippingOption, { + id: `simple-so-${Math.random() * 1000}`, + name: data.name || "Test Method", + is_return: data.is_return ?? false, + region_id: data.region_id, + provider_id: "test-ful", + profile_id: data.is_giftcard ? gcProfile.id : defaultProfile.id, + price_type: ShippingOptionPriceType.FLAT_RATE, + data: {}, + amount: typeof data.price !== "undefined" ? data.price : 500, + }) + const option = await manager.save(created) + return option +} diff --git a/integration-tests/plugins/factories/simple-shipping-tax-rate-factory.ts b/integration-tests/plugins/factories/simple-shipping-tax-rate-factory.ts new file mode 100644 index 0000000000..1ce21cdda9 --- /dev/null +++ b/integration-tests/plugins/factories/simple-shipping-tax-rate-factory.ts @@ -0,0 +1,48 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { ShippingTaxRate, TaxRate } from "@medusajs/medusa" + +type RateFactoryData = { + region_id: string + rate?: number | null + code?: string + name?: string +} + +export type ShippingTaxRateFactoryData = { + shipping_option_id: string + rate: RateFactoryData | string +} + +export const simpleShippingTaxRateFactory = async ( + connection: Connection, + data: ShippingTaxRateFactoryData, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + let rateId: string + if (typeof data.rate === "string") { + rateId = data.rate + } else { + const newRate = manager.create(TaxRate, { + region_id: data.rate.region_id, + rate: data.rate.rate, + code: data.rate.code || "sales_tax", + name: data.rate.name || "Sales Tax", + }) + const rate = await manager.save(newRate) + rateId = rate.id + } + + const toSave = manager.create(ShippingTaxRate, { + shipping_option_id: data.shipping_option_id, + rate_id: rateId, + }) + + return await manager.save(toSave) +} diff --git a/integration-tests/plugins/factories/simple-store-factory.ts b/integration-tests/plugins/factories/simple-store-factory.ts new file mode 100644 index 0000000000..f6dc2af393 --- /dev/null +++ b/integration-tests/plugins/factories/simple-store-factory.ts @@ -0,0 +1,24 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { Store } from "@medusajs/medusa" + +export type StoreFactoryData = { + swap_link_template?: string +} + +export const simpleStoreFactory = async ( + connection: Connection, + data: StoreFactoryData = {}, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + const store = await manager.findOne(Store) + + store.swap_link_template = data.swap_link_template ?? "something/{cart_id}" + + return await manager.save(store) +} diff --git a/integration-tests/plugins/factories/simple-tax-rate-factory.ts b/integration-tests/plugins/factories/simple-tax-rate-factory.ts new file mode 100644 index 0000000000..44987da67e --- /dev/null +++ b/integration-tests/plugins/factories/simple-tax-rate-factory.ts @@ -0,0 +1,32 @@ +import { Connection } from "typeorm" +import faker from "faker" +import { TaxRate } from "@medusajs/medusa" + +export type TaxRateFactoryData = { + region_id: string + rate?: number | null + code?: string + name?: string +} + +export const simpleTaxRateFactory = async ( + connection: Connection, + data: TaxRateFactoryData, + seed?: number +): Promise => { + if (typeof seed !== "undefined") { + faker.seed(seed) + } + + const manager = connection.manager + + const toSave = manager.create(TaxRate, { + region_id: data.region_id, + rate: + data.rate ?? faker.datatype.number({ min: 0, max: 100, precision: 2 }), + code: data.code || faker.random.word(), + name: data.name || faker.random.words(2), + }) + + return await manager.save(toSave) +} diff --git a/integration-tests/plugins/helpers/admin-seeder.js b/integration-tests/plugins/helpers/admin-seeder.js new file mode 100644 index 0000000000..660bad0470 --- /dev/null +++ b/integration-tests/plugins/helpers/admin-seeder.js @@ -0,0 +1,18 @@ +const Scrypt = require("scrypt-kdf") +const { User } = require("@medusajs/medusa") + +module.exports = async (connection, data = {}) => { + const manager = connection.manager + + const buf = await Scrypt.kdf("secret_password", { logN: 1, r: 1, p: 1 }) + const password_hash = buf.toString("base64") + + await manager.insert(User, { + id: "admin_user", + email: "admin@medusa.js", + api_token: "test_token", + role: "admin", + password_hash, + ...data, + }) +} diff --git a/integration-tests/plugins/helpers/call-helpers.js b/integration-tests/plugins/helpers/call-helpers.js new file mode 100644 index 0000000000..9a9233d42d --- /dev/null +++ b/integration-tests/plugins/helpers/call-helpers.js @@ -0,0 +1,100 @@ +const { useApi } = require("../../helpers/use-api") + +const header = { + headers: { + authorization: "Bearer test_token", + }, +} + +const resolveCall = async (path, payload, header) => { + const api = useApi() + let res + try { + const resp = await api.post(path, payload, header) + res = resp.status + } catch (expectedException) { + try { + res = expectedException.response.status + } catch (_) { + console.error(expectedException) + } + } + return res +} + +const determineFail = (actual, expected, path) => { + if (expected !== actual) { + console.log(`failed at path : ${path}`) + } + expect(actual).toEqual(expected) +} + +/** + * Allows you to wrap a Call function so that you may reuse some input values. + * @param {Function} fun - the function to call with partial information + * @param {Object} input - the constant input which we want to supply now + * @returns + */ +module.exports.partial = function (fun, input = {}) { + return async (remaining) => await fun({ ...remaining, ...input }) +} + +/** + * Allows you to assert a specific code result from a POST call. + * @param {Object} input - the information needed to make the call + * (path & payload) and the expected code (code) + */ +module.exports.expectPostCallToReturn = async function ( + input = { + code, + path, + payload: {}, + } +) { + const res = await resolveCall(input.path, input.payload, header) + determineFail(res, input.code, input.path) +} + +/** + * Allows you to assert a specific code result from multiple POST + * calls. + * @param {Object} input - the collection of objects to execute + * calls from (col), a function which yields the path (pathf), + * and another one which provides the payload (payloadf), as + * well as the code (code) which we want to assert. + */ +module.exports.expectAllPostCallsToReturn = async function ( + input = { + code, + col, + pathf, + payloadf, + } +) { + for (const i of input.col) { + const res = await resolveCall( + input.pathf(i), + input.payloadf ? input.payloadf(i) : {}, + header + ) + determineFail(res, input.code, input.pathf(i)) + } +} + +/** + * Allows you to retrieve a specific object the response + * from get call, + * and simultaneously assert that the call was successful. + * @param {Object} param0 - contains the path which to + * call (path), and the object within the response.data (get) + * we want to retrieve. + * @returns {Object} found within response.data corresponding + * to the get parameter provided. + */ +module.exports.callGet = async function ({ path, get }) { + const api = useApi() + const res = await api.get(path, header) + + determineFail(res.status, 200, path) + return res?.data[get] +} diff --git a/integration-tests/plugins/helpers/cart-seeder.js b/integration-tests/plugins/helpers/cart-seeder.js new file mode 100644 index 0000000000..da7eb55b83 --- /dev/null +++ b/integration-tests/plugins/helpers/cart-seeder.js @@ -0,0 +1,536 @@ +const { + Customer, + Region, + Cart, + DiscountRule, + Discount, + ShippingProfile, + ShippingOption, + ShippingMethod, + Address, + Product, + ProductVariant, + MoneyAmount, + LineItem, + Payment, + PaymentSession, +} = require("@medusajs/medusa") + +module.exports = async (connection, data = {}) => { + const yesterday = ((today) => new Date(today.setDate(today.getDate() - 1)))( + new Date() + ) + const tomorrow = ((today) => new Date(today.setDate(today.getDate() + 1)))( + new Date() + ) + const tenDaysAgo = ((today) => new Date(today.setDate(today.getDate() - 10)))( + new Date() + ) + const tenDaysFromToday = ((today) => + new Date(today.setDate(today.getDate() + 10)))(new Date()) + + const manager = connection.manager + + const defaultProfile = await manager.findOne(ShippingProfile, { + type: "default", + }) + + const gcProfile = await manager.findOne(ShippingProfile, { + type: "gift_card", + }) + + await manager.insert(Address, { + id: "test-general-address", + first_name: "superman", + country_code: "us", + }) + + const r = manager.create(Region, { + id: "test-region", + name: "Test Region", + currency_code: "usd", + tax_rate: 0, + }) + + // Region with multiple countries + const regionWithMultipleCoutries = manager.create(Region, { + id: "test-region-multiple", + name: "Test Region", + currency_code: "eur", + tax_rate: 0, + }) + + await manager.save(regionWithMultipleCoutries) + await manager.query( + `UPDATE "country" SET region_id='test-region-multiple' WHERE iso_2 = 'no'` + ) + await manager.query( + `UPDATE "country" SET region_id='test-region-multiple' WHERE iso_2 = 'dk'` + ) + + const freeRule = manager.create(DiscountRule, { + id: "free-shipping-rule", + description: "Free shipping rule", + type: "free_shipping", + value: 100, + allocation: "total", + }) + + const freeDisc = manager.create(Discount, { + id: "free-shipping", + code: "FREE_SHIPPING", + is_dynamic: false, + is_disabled: false, + }) + + freeDisc.regions = [r] + freeDisc.rule = freeRule + await manager.save(freeDisc) + + const tenPercentRule = manager.create(DiscountRule, { + id: "tenpercent-rule", + description: "Ten percent rule", + type: "percentage", + value: 10, + allocation: "total", + }) + + const tenPercent = manager.create(Discount, { + id: "10Percent", + code: "10PERCENT", + is_dynamic: false, + is_disabled: false, + starts_at: tenDaysAgo, + ends_at: tenDaysFromToday, + }) + + tenPercent.regions = [r] + tenPercent.rule = tenPercentRule + await manager.save(tenPercent) + + const dUsageLimit = await manager.create(Discount, { + id: "test-discount-usage-limit", + code: "SPENT", + is_dynamic: false, + is_disabled: false, + usage_limit: 10, + usage_count: 10, + }) + + const drUsage = await manager.create(DiscountRule, { + id: "test-discount-rule-usage-limit", + description: "Created", + type: "fixed", + value: 10000, + allocation: "total", + }) + + dUsageLimit.rule = drUsage + dUsageLimit.regions = [r] + + await manager.save(dUsageLimit) + + const d = await manager.create(Discount, { + id: "test-discount", + code: "CREATED", + is_dynamic: false, + is_disabled: false, + }) + + const dr = await manager.create(DiscountRule, { + id: "test-discount-rule", + description: "Created", + type: "fixed", + value: 10000, + allocation: "total", + }) + + d.rule = dr + d.regions = [r] + + await manager.save(d) + + const usedDiscount = manager.create(Discount, { + id: "used-discount", + code: "USED", + is_dynamic: false, + is_disabled: false, + usage_limit: 1, + usage_count: 1, + }) + + await manager.save(usedDiscount) + + const expiredRule = manager.create(DiscountRule, { + id: "expiredRule", + description: "expired rule", + type: "fixed", + value: 100, + allocation: "total", + }) + + const expiredDisc = manager.create(Discount, { + id: "expiredDisc", + code: "EXP_DISC", + is_dynamic: false, + is_disabled: false, + starts_at: tenDaysAgo, + ends_at: yesterday, + }) + + expiredDisc.regions = [r] + expiredDisc.rule = expiredRule + await manager.save(expiredDisc) + + const prematureRule = manager.create(DiscountRule, { + id: "prematureRule", + description: "premature rule", + type: "fixed", + value: 100, + allocation: "total", + }) + + const prematureDiscount = manager.create(Discount, { + id: "prematureDiscount", + code: "PREM_DISC", + is_dynamic: false, + is_disabled: false, + starts_at: tomorrow, + ends_at: tenDaysFromToday, + }) + + prematureDiscount.regions = [r] + prematureDiscount.rule = prematureRule + await manager.save(prematureDiscount) + + const invalidDynamicRule = manager.create(DiscountRule, { + id: "invalidDynamicRule", + description: "invalidDynamic rule", + type: "fixed", + value: 100, + allocation: "total", + }) + + const invalidDynamicDiscount = manager.create(Discount, { + id: "invalidDynamicDiscount", + code: "INV_DYN_DISC", + is_dynamic: true, + is_disabled: false, + starts_at: tenDaysAgo, + ends_at: tenDaysFromToday, + valid_duration: "P1D", // one day + }) + + invalidDynamicDiscount.regions = [r] + invalidDynamicDiscount.rule = invalidDynamicRule + await manager.save(invalidDynamicDiscount) + + const DynamicRule = manager.create(DiscountRule, { + id: "DynamicRule", + description: "Dynamic rule", + type: "fixed", + value: 10000, + allocation: "total", + }) + + const DynamicDiscount = manager.create(Discount, { + id: "DynamicDiscount", + code: "DYN_DISC", + is_dynamic: true, + is_disabled: false, + starts_at: tenDaysAgo, + ends_at: tenDaysFromToday, + valid_duration: "P1M", //one month + }) + + DynamicDiscount.regions = [r] + DynamicDiscount.rule = DynamicRule + await manager.save(DynamicDiscount) + + await manager.query( + `UPDATE "country" SET region_id='test-region' WHERE iso_2 = 'us'` + ) + + await manager.insert(Customer, { + id: "test-customer", + email: "test@email.com", + }) + + await manager.insert(Customer, { + id: "test-customer-2", + email: "test-2@email.com", + }) + + await manager.insert(Customer, { + id: "some-customer", + email: "some-customer@email.com", + }) + + await manager.insert(ShippingOption, { + id: "test-option", + name: "test-option", + provider_id: "test-ful", + region_id: "test-region", + profile_id: defaultProfile.id, + price_type: "flat_rate", + amount: 1000, + data: {}, + }) + + await manager.insert(ShippingOption, { + id: "gc-option", + name: "Digital copy", + provider_id: "test-ful", + region_id: "test-region", + profile_id: gcProfile.id, + price_type: "flat_rate", + amount: 0, + data: {}, + }) + + await manager.insert(ShippingOption, { + id: "test-option-2", + name: "test-option-2", + provider_id: "test-ful", + region_id: "test-region", + profile_id: defaultProfile.id, + price_type: "flat_rate", + amount: 500, + data: {}, + }) + + await manager.insert(Product, { + id: "giftcard-product", + title: "Giftcard", + is_giftcard: true, + discountable: false, + profile_id: gcProfile.id, + options: [{ id: "denom", title: "Denomination" }], + }) + + await manager.insert(ProductVariant, { + id: "giftcard-denom", + title: "1000", + product_id: "giftcard-product", + inventory_quantity: 1, + options: [ + { + option_id: "denom", + value: "1000", + }, + ], + }) + + await manager.insert(Product, { + id: "test-product", + title: "test product", + profile_id: defaultProfile.id, + options: [{ id: "test-option", title: "Size" }], + }) + + await manager.insert(ProductVariant, { + id: "test-variant", + title: "test variant", + product_id: "test-product", + inventory_quantity: 1, + options: [ + { + option_id: "test-option", + value: "Size", + }, + ], + }) + + await manager.insert(ProductVariant, { + id: "test-variant-2", + title: "test variant 2", + product_id: "test-product", + inventory_quantity: 0, + options: [ + { + option_id: "test-option", + value: "Size", + }, + ], + }) + + const ma = manager.create(MoneyAmount, { + variant_id: "test-variant", + currency_code: "usd", + amount: 1000, + }) + + await manager.save(ma) + + const ma2 = manager.create(MoneyAmount, { + variant_id: "test-variant-2", + currency_code: "usd", + amount: 8000, + }) + + await manager.save(ma2) + + const ma3 = manager.create(MoneyAmount, { + variant_id: "giftcard-denom", + currency_code: "usd", + amount: 1000, + }) + + await manager.save(ma3) + + const cart = manager.create(Cart, { + id: "test-cart", + customer_id: "some-customer", + email: "some-customer@email.com", + shipping_address: { + id: "test-shipping-address", + first_name: "lebron", + country_code: "us", + }, + region_id: "test-region", + currency_code: "usd", + items: [], + }) + + await manager.save(cart) + + const cart2 = manager.create(Cart, { + id: "test-cart-2", + customer_id: "some-customer", + email: "some-customer@email.com", + shipping_address: { + id: "test-shipping-address", + first_name: "lebron", + country_code: "us", + }, + region_id: "test-region", + currency_code: "usd", + completed_at: null, + items: [], + }) + + const swapCart = manager.create(Cart, { + id: "swap-cart", + type: "swap", + customer_id: "some-customer", + email: "some-customer@email.com", + shipping_address: { + id: "test-shipping-address", + first_name: "lebron", + country_code: "us", + }, + region_id: "test-region", + currency_code: "usd", + completed_at: null, + items: [], + metadata: { + swap_id: "test-swap", + }, + }) + + const pay = manager.create(Payment, { + id: "test-payment", + amount: 10000, + currency_code: "usd", + amount_refunded: 0, + provider_id: "test-pay", + data: {}, + }) + + await manager.save(pay) + + cart2.payment = pay + + await manager.save(cart2) + const swapPay = manager.create(Payment, { + id: "test-swap-payment", + amount: 10000, + currency_code: "usd", + amount_refunded: 0, + provider_id: "test-pay", + data: {}, + }) + + await manager.save(pay) + await manager.save(swapPay) + + cart2.payment = pay + swapCart.payment = swapPay + + await manager.save(cart2) + await manager.save(swapCart) + + await manager.insert(PaymentSession, { + id: "test-session", + cart_id: "test-cart-2", + provider_id: "test-pay", + is_selected: true, + data: {}, + status: "authorized", + }) + + await manager.insert(PaymentSession, { + id: "test-swap-session", + cart_id: "swap-cart", + provider_id: "test-pay", + is_selected: true, + data: {}, + status: "authorized", + }) + + await manager.insert(ShippingMethod, { + id: "test-method", + shipping_option_id: "test-option", + cart_id: "test-cart", + price: 1000, + data: {}, + }) + + const li = manager.create(LineItem, { + id: "test-item", + title: "Line Item", + description: "Line Item Desc", + thumbnail: "https://test.js/1234", + unit_price: 8000, + quantity: 1, + variant_id: "test-variant", + cart_id: "test-cart-2", + }) + await manager.save(li) + + const cart3 = manager.create(Cart, { + id: "test-cart-3", + customer_id: "some-customer", + email: "some-customer@email.com", + shipping_address: { + id: "test-shipping-address", + first_name: "lebron", + country_code: "us", + }, + region_id: "test-region", + currency_code: "usd", + completed_at: null, + items: [], + }) + await manager.save(cart3) + + await manager.insert(ShippingMethod, { + id: "test-method-2", + shipping_option_id: "test-option", + cart_id: "test-cart-3", + price: 0, + data: {}, + }) + + const li2 = manager.create(LineItem, { + id: "test-item-2", + title: "Line Item", + description: "Line Item Desc", + thumbnail: "https://test.js/1234", + unit_price: 8000, + quantity: 1, + variant_id: "test-variant", + cart_id: "test-cart-3", + }) + await manager.save(li2) +} diff --git a/integration-tests/plugins/helpers/claim-seeder.js b/integration-tests/plugins/helpers/claim-seeder.js new file mode 100644 index 0000000000..ae19e09e68 --- /dev/null +++ b/integration-tests/plugins/helpers/claim-seeder.js @@ -0,0 +1,118 @@ +const { + ClaimOrder, + Order, + LineItem, + Fulfillment, + Return, +} = require("@medusajs/medusa") + +module.exports = async (connection, data = {}) => { + const manager = connection.manager + + let orderWithClaim = manager.create(Order, { + id: "order-with-claim", + customer_id: "test-customer", + email: "test@email.com", + payment_status: "captured", + fulfillment_status: "fulfilled", + billing_address: { + id: "test-billing-address", + first_name: "lebron", + }, + shipping_address: { + id: "test-shipping-address", + first_name: "lebron", + country_code: "us", + }, + region_id: "test-region", + currency_code: "usd", + tax_rate: 0, + discounts: [], + payments: [ + { + id: "test-payment-for-claim-order", + amount: 10000, + currency_code: "usd", + amount_refunded: 0, + provider_id: "test-pay", + data: {}, + }, + ], + items: [], + ...data, + }) + + await manager.save(orderWithClaim) + + const li = manager.create(LineItem, { + id: "test-item-co-2", + fulfilled_quantity: 1, + title: "Line Item", + description: "Line Item Desc", + thumbnail: "https://test.js/1234", + unit_price: 8000, + quantity: 1, + variant_id: "test-variant", + order_id: orderWithClaim.id, + }) + + await manager.save(li) + + const li2 = manager.create(LineItem, { + id: "test-item-co-3", + fulfilled_quantity: 4, + title: "Line Item", + description: "Line Item Desc", + thumbnail: "https://test.js/1234", + unit_price: 8000, + quantity: 4, + variant_id: "test-variant", + order_id: orderWithClaim.id, + }) + + await manager.save(li2) + + const claimWithFulfillment = manager.create(ClaimOrder, { + id: "claim-w-f", + type: "replace", + payment_status: "na", + fulfillment_status: "not_fulfilled", + order_id: "order-with-claim", + ...data, + }) + + const ful1 = manager.create(Fulfillment, { + id: "fulfillment-co-1", + data: {}, + provider_id: "test-ful", + }) + + const ful2 = manager.create(Fulfillment, { + id: "fulfillment-co-2", + data: {}, + provider_id: "test-ful", + }) + + claimWithFulfillment.fulfillments = [ful1, ful2] + + await manager.save(claimWithFulfillment) + + const claimWithReturn = manager.create(ClaimOrder, { + id: "claim-w-r", + type: "replace", + payment_status: "na", + fulfillment_status: "not_fulfilled", + order_id: "order-with-claim", + ...data, + }) + + await manager.save(claimWithReturn) + + await manager.insert(Return, { + id: "return-id-2", + claim_order_id: "claim-w-r", + status: "requested", + refund_amount: 0, + data: {}, + }) +} diff --git a/integration-tests/plugins/helpers/customer-seeder.js b/integration-tests/plugins/helpers/customer-seeder.js new file mode 100644 index 0000000000..acef948bbd --- /dev/null +++ b/integration-tests/plugins/helpers/customer-seeder.js @@ -0,0 +1,33 @@ +const { Customer, Address } = require("@medusajs/medusa") + +module.exports = async (connection, data = {}) => { + const manager = connection.manager + + await manager.insert(Customer, { + id: "test-customer-1", + email: "test1@email.com", + }) + + await manager.insert(Customer, { + id: "test-customer-2", + email: "test2@email.com", + }) + + await manager.insert(Customer, { + id: "test-customer-3", + email: "test3@email.com", + }) + + await manager.insert(Customer, { + id: "test-customer-has_account", + email: "test4@email.com", + has_account: true, + }) + + await manager.insert(Address, { + id: "test-address", + first_name: "Lebron", + last_name: "James", + customer_id: "test-customer-1", + }) +} diff --git a/integration-tests/plugins/helpers/discount-seeder.js b/integration-tests/plugins/helpers/discount-seeder.js new file mode 100644 index 0000000000..cc623bab33 --- /dev/null +++ b/integration-tests/plugins/helpers/discount-seeder.js @@ -0,0 +1,35 @@ +const { + ShippingProfile, + Region, + Discount, + DiscountRule, +} = require("@medusajs/medusa") +module.exports = async (connection, data = {}) => { + const manager = connection.manager + + await manager.insert(Region, { + id: "test-region", + name: "Test Region", + currency_code: "usd", + tax_rate: 0, + payment_providers: [ + { + id: "test-pay", + is_installed: true, + }, + ], + }) + + await manager.insert(Region, { + id: "test-region-2", + name: "Test Region 2", + currency_code: "eur", + tax_rate: 0, + payment_providers: [ + { + id: "test-pay", + is_installed: true, + }, + ], + }) +} diff --git a/integration-tests/plugins/helpers/draft-order-seeder.js b/integration-tests/plugins/helpers/draft-order-seeder.js new file mode 100644 index 0000000000..19b63b0d7c --- /dev/null +++ b/integration-tests/plugins/helpers/draft-order-seeder.js @@ -0,0 +1,261 @@ +const { + ShippingProfile, + Customer, + MoneyAmount, + ShippingOption, + ShippingOptionRequirement, + Product, + ProductVariant, + Region, + Address, + Cart, + PaymentSession, + DraftOrder, + Discount, + DiscountRule, + Payment, +} = require("@medusajs/medusa") + +module.exports = async (connection, data = {}) => { + const manager = connection.manager + + const defaultProfile = await manager.findOne(ShippingProfile, { + type: "default", + }) + + await manager.insert(Product, { + id: "test-product", + title: "test product", + profile_id: defaultProfile.id, + options: [{ id: "test-option", title: "Size" }], + }) + + await manager.insert(Address, { + id: "oli-shipping", + first_name: "oli", + last_name: "test", + country_code: "us", + }) + + await manager.insert(Product, { + id: "test-product-2", + title: "test product 2", + profile_id: defaultProfile.id, + options: [{ id: "test-option-color", title: "Color" }], + }) + + await manager.insert(ProductVariant, { + id: "test-variant", + title: "test variant", + product_id: "test-product", + inventory_quantity: 1, + options: [ + { + option_id: "test-option", + value: "Size", + }, + ], + }) + + await manager.insert(ProductVariant, { + id: "test-variant-2", + title: "test variant-2", + product_id: "test-product-2", + inventory_quantity: 4, + options: [ + { + option_id: "test-option-color", + value: "Color", + }, + ], + }) + + const ma = manager.create(MoneyAmount, { + variant_id: "test-variant", + currency_code: "usd", + amount: 8000, + }) + await manager.save(ma) + + const ma2 = manager.create(MoneyAmount, { + variant_id: "test-variant-2", + currency_code: "usd", + amount: 10000, + }) + + await manager.save(ma2) + + await manager.insert(Region, { + id: "test-region", + name: "Test Region", + currency_code: "usd", + tax_rate: 0, + payment_providers: [ + { + id: "test-pay", + is_installed: true, + }, + ], + }) + + await manager.insert(Region, { + id: "test-region-2", + name: "Test Region 2", + currency_code: "eur", + tax_rate: 0, + payment_providers: [ + { + id: "test-pay", + is_installed: true, + }, + ], + }) + + await manager.insert(DiscountRule, { + id: "discount_rule_id", + description: "test description", + value: 10, + allocation: "total", + type: "percentage", + }) + + const d = manager.create(Discount, { + id: "test-discount", + code: "TEST", + is_dynamic: false, + is_disabled: false, + rule_id: "discount_rule_id", + }) + + d.regions = [ + { + id: "test-region", + name: "Test Region", + currency_code: "usd", + tax_rate: 0, + }, + ] + + await manager.save(d) + + await manager.query( + `UPDATE "country" SET region_id='test-region' WHERE iso_2 = 'us'` + ) + + await manager.query( + `UPDATE "country" SET region_id='test-region-2' WHERE iso_2 = 'de'` + ) + + await manager.insert(Customer, { + id: "oli-test", + email: "oli@test.dk", + }) + + await manager.insert(Customer, { + id: "lebron-james", + email: "lebron@james.com", + }) + + await manager.insert(ShippingOption, { + id: "test-option", + name: "test-option", + provider_id: "test-ful", + region_id: "test-region", + profile_id: defaultProfile.id, + price_type: "flat_rate", + amount: 1000, + data: {}, + }) + + await manager.insert(ShippingOption, { + id: "test-option-req", + name: "test-option-req", + provider_id: "test-ful", + region_id: "test-region", + profile_id: defaultProfile.id, + price_type: "flat_rate", + amount: 1000, + data: {}, + }) + + await manager.insert(ShippingOptionRequirement, { + id: "option-req", + shipping_option_id: "test-option-req", + type: "min_subtotal", + amount: 10, + }) + + const c = manager.create(Cart, { + id: "test-cart", + customer_id: "oli-test", + email: "oli@test.dk", + shipping_address_id: "oli-shipping", + region_id: "test-region", + currency_code: "usd", + payment_sessions: [], + items: [ + { + id: "test-item", + fulfilled_quantity: 1, + title: "Line Item", + description: "Line Item Desc", + thumbnail: "https://test.js/1234", + unit_price: 8000, + quantity: 1, + variant_id: "test-variant", + }, + ], + type: "draft_order", + metadata: { draft_order_id: "test-draft-order" }, + }) + + const pay = manager.create(Payment, { + id: "test-payment", + amount: 10000, + currency_code: "usd", + amount_refunded: 0, + provider_id: "test-pay", + data: {}, + }) + + await manager.save(pay) + + c.payment = pay + + await manager.save(c) + + await manager.insert(PaymentSession, { + id: "test-session", + cart_id: "test-cart", + provider_id: "test-pay", + is_selected: true, + data: {}, + status: "authorized", + }) + + const draftOrder = manager.create(DraftOrder, { + id: "test-draft-order", + status: "open", + display_id: 4, + cart_id: "test-cart", + customer_id: "oli-test", + items: [ + { + id: "test-item", + fulfilled_quantity: 1, + title: "Line Item", + description: "Line Item Desc", + thumbnail: "https://test.js/1234", + unit_price: 8000, + quantity: 1, + variant_id: "test-variant", + }, + ], + email: "oli@test.dk", + region_id: "test-region", + discounts: [], + ...data, + }) + + await manager.save(draftOrder) +} diff --git a/integration-tests/plugins/helpers/order-seeder.js b/integration-tests/plugins/helpers/order-seeder.js new file mode 100644 index 0000000000..2029653dc2 --- /dev/null +++ b/integration-tests/plugins/helpers/order-seeder.js @@ -0,0 +1,396 @@ +const { + Customer, + Discount, + DiscountRule, + LineItem, + MoneyAmount, + Order, + Payment, + Product, + ProductVariant, + Region, + ShippingMethod, + ShippingOption, + ShippingProfile, + Swap, +} = require("@medusajs/medusa") + +module.exports = async (connection, data = {}) => { + const manager = connection.manager + + const defaultProfile = await manager.findOne(ShippingProfile, { + type: "default", + }) + + await manager.insert(Product, { + id: "test-product", + title: "test product", + profile_id: defaultProfile.id, + options: [{ id: "test-option", title: "Size" }], + }) + + await manager.insert(ProductVariant, { + id: "test-variant", + title: "test variant", + product_id: "test-product", + inventory_quantity: 1, + options: [ + { + option_id: "test-option", + value: "Size", + }, + ], + }) + + await manager.insert(ProductVariant, { + id: "test-variant-2", + title: "Swap product", + product_id: "test-product", + inventory_quantity: 1, + options: [ + { + option_id: "test-option", + value: "Large", + }, + ], + }) + + const ma2 = manager.create(MoneyAmount, { + variant_id: "test-variant-2", + currency_code: "usd", + amount: 8000, + }) + await manager.save(ma2) + + const ma = manager.create(MoneyAmount, { + variant_id: "test-variant", + currency_code: "usd", + amount: 8000, + }) + await manager.save(ma) + + await manager.insert(Region, { + id: "test-region", + name: "Test Region", + currency_code: "usd", + tax_rate: 0, + }) + + await manager.query( + `UPDATE "country" SET region_id='test-region' WHERE iso_2 = 'us'` + ) + + await manager.insert(Customer, { + id: "test-customer", + email: "test@email.com", + }) + + await manager.insert(ShippingOption, { + id: "test-option", + name: "test-option", + provider_id: "test-ful", + region_id: "test-region", + profile_id: defaultProfile.id, + price_type: "flat_rate", + amount: 1000, + data: {}, + }) + + await manager.insert(ShippingOption, { + id: "test-return-option", + name: "Test ret", + profile_id: defaultProfile.id, + region_id: "test-region", + provider_id: "test-ful", + data: {}, + price_type: "flat_rate", + amount: 1000, + is_return: true, + }) + + const order = manager.create(Order, { + id: "test-order", + customer_id: "test-customer", + email: "test@email.com", + payment_status: "captured", + fulfillment_status: "fulfilled", + billing_address: { + id: "test-billing-address", + first_name: "lebron", + }, + shipping_address: { + id: "test-shipping-address", + first_name: "lebron", + country_code: "us", + }, + region_id: "test-region", + currency_code: "usd", + tax_rate: 0, + discounts: [ + { + id: "test-discount", + code: "TEST134", + is_dynamic: false, + rule: { + id: "test-rule", + description: "Test Discount", + type: "percentage", + value: 10, + allocation: "total", + }, + is_disabled: false, + regions: [ + { + id: "test-region", + }, + ], + }, + ], + payments: [ + { + id: "test-payment", + amount: 10000, + currency_code: "usd", + amount_refunded: 0, + provider_id: "test-pay", + data: {}, + }, + ], + items: [], + ...data, + }) + + await manager.save(order) + + const li = manager.create(LineItem, { + id: "test-item", + fulfilled_quantity: 1, + returned_quantity: 0, + title: "Line Item", + description: "Line Item Desc", + thumbnail: "https://test.js/1234", + unit_price: 8000, + quantity: 1, + variant_id: "test-variant", + order_id: "test-order", + }) + + await manager.save(li) + + await manager.insert(ShippingMethod, { + id: "test-method", + order_id: "test-order", + shipping_option_id: "test-option", + price: 1000, + data: {}, + }) + + const orderTemplate = () => { + return { + customer_id: "test-customer", + email: "test@gmail.com", + payment_status: "not_paid", + fulfillment_status: "not_fulfilled", + region_id: "test-region", + currency_code: "usd", + tax_rate: 0, + ...data, + } + } + + const paymentTemplate = () => { + return { + amount: 10000, + currency_code: "usd", + provider_id: "test-pay", + data: {}, + } + } + + const orderWithClaim = manager.create(Order, { + id: "test-order-w-c", + claims: [ + { + type: "replace", + id: "claim-1", + payment_status: "na", + fulfillment_status: "not_fulfilled", + payment_provider: "test-pay", + }, + ], + ...orderTemplate(), + }) + + await manager.save(orderWithClaim) + + await manager.insert(Payment, { + order_id: "test-order-w-c", + id: "o-pay1", + ...paymentTemplate(), + }) + + const orderWithSwap = manager.create(Order, { + id: "test-order-w-s", + ...orderTemplate(), + }) + + await manager.save(orderWithSwap) + + await manager.insert(Payment, { + order_id: "test-order-w-s", + id: "o-pay2", + ...paymentTemplate(), + }) + + const swap1 = manager.create(Swap, { + id: "swap-1", + order_id: "test-order-w-s", + fulfillment_status: "not_fulfilled", + payment_status: "not_paid", + }) + + const pay1 = manager.create(Payment, { + id: "pay1", + ...paymentTemplate(), + }) + + swap1.payment = pay1 + + const swap2 = manager.create(Swap, { + id: "swap-2", + order_id: "test-order-w-s", + fulfillment_status: "not_fulfilled", + payment_status: "not_paid", + }) + + const pay2 = manager.create(Payment, { + id: "pay2", + ...paymentTemplate(), + }) + + swap2.payment = pay2 + + await manager.save(swap1) + await manager.save(swap2) + + const orderWithFulfillment = manager.create(Order, { + id: "test-order-w-f", + fulfillments: [ + { + id: "fulfillment-on-order-1", + data: {}, + provider_id: "test-ful", + }, + { + id: "fulfillment-on-order-2", + data: {}, + provider_id: "test-ful", + }, + ], + ...orderTemplate(), + }) + + await manager.save(orderWithFulfillment) + + await manager.insert(Payment, { + order_id: "test-order-w-f", + id: "o-pay3", + ...paymentTemplate(), + }) + + const orderWithReturn = manager.create(Order, { + id: "test-order-w-r", + returns: [ + { + id: "return-on-order-1", + refund_amount: 0, + }, + { + id: "return-on-order-2", + refund_amount: 0, + }, + ], + ...orderTemplate(), + }) + + await manager.save(orderWithReturn) + + await manager.insert(Payment, { + order_id: "test-order-w-r", + id: "o-pay4", + ...paymentTemplate(), + }) + + const drule = manager.create(DiscountRule, { + id: "test-rule", + description: "Test Discount", + type: "percentage", + value: 10, + allocation: "total", + }) + + const discount = manager.create(Discount, { + id: "test-discount-o", + code: "TEST1234", + is_dynamic: false, + rule: drule, + is_disabled: false, + regions: [ + { + id: "test-region", + }, + ], + }) + await manager.save(discount) + + const payment = manager.create(Payment, { + id: "test-payment-d", + amount: 10000, + currency_code: "usd", + amount_refunded: 0, + provider_id: "test-pay", + captured_at: new Date(), + data: {}, + }) + + const discountedOrder = manager.create(Order, { + id: "discount-order", + customer_id: "test-customer", + email: "test-discount@email.com", + payment_status: "captured", + fulfillment_status: "fulfilled", + discounts: [discount], + billing_address: { + id: "test-discount-billing-address", + first_name: "lebron", + }, + shipping_address: { + id: "test-shipping-address", + first_name: "lebron", + country_code: "us", + }, + region_id: "test-region", + currency_code: "usd", + tax_rate: 0, + payments: [payment], + items: [], + ...data, + }) + + await manager.save(discountedOrder) + + const dli = manager.create(LineItem, { + id: "test-item-1", + fulfilled_quantity: 1, + returned_quantity: 0, + title: "Line Item", + description: "Line Item Desc", + thumbnail: "https://test.js/1234", + unit_price: 8000, + quantity: 1, + variant_id: "test-variant", + order_id: "discount-order", + }) + + await manager.save(dli) +} diff --git a/integration-tests/plugins/helpers/product-seeder.js b/integration-tests/plugins/helpers/product-seeder.js new file mode 100644 index 0000000000..aef5729fe7 --- /dev/null +++ b/integration-tests/plugins/helpers/product-seeder.js @@ -0,0 +1,286 @@ +const { + ProductCollection, + ProductTag, + ProductType, + ProductOption, + Region, + Product, + ShippingProfile, + ProductVariant, + Image, +} = require("@medusajs/medusa") + +module.exports = async (connection, data = {}) => { + const manager = connection.manager + + const defaultProfile = await manager.findOne(ShippingProfile, { + type: "default", + }) + + const coll = manager.create(ProductCollection, { + id: "test-collection", + handle: "test-collection", + title: "Test collection", + }) + + await manager.save(coll) + + const coll1 = manager.create(ProductCollection, { + id: "test-collection1", + handle: "test-collection1", + title: "Test collection 1", + }) + + await manager.save(coll1) + + const coll2 = manager.create(ProductCollection, { + id: "test-collection2", + handle: "test-collection2", + title: "Test collection 2", + }) + + await manager.save(coll2) + + const tag = manager.create(ProductTag, { + id: "tag1", + value: "123", + }) + + await manager.save(tag) + + const tag3 = manager.create(ProductTag, { + id: "tag3", + value: "123", + }) + + await manager.save(tag3) + + const tag4 = manager.create(ProductTag, { + id: "tag4", + value: "123", + }) + + await manager.save(tag4) + + const type = manager.create(ProductType, { + id: "test-type", + value: "test-type", + }) + + await manager.save(type) + + const image = manager.create(Image, { + id: "test-image", + url: "test-image.png", + }) + + await manager.save(image) + + await manager.insert(Region, { + id: "test-region", + name: "Test Region", + currency_code: "usd", + tax_rate: 0, + }) + + const p = manager.create(Product, { + id: "test-product", + handle: "test-product", + title: "Test product", + profile_id: defaultProfile.id, + description: "test-product-description", + collection_id: "test-collection", + type: { id: "test-type", value: "test-type" }, + tags: [ + { id: "tag1", value: "123" }, + { tag: "tag2", value: "456" }, + ], + }) + + p.images = [image] + + await manager.save(p) + + await manager.save(ProductOption, { + id: "test-option", + title: "test-option", + product_id: "test-product", + }) + + const variant1 = await manager.create(ProductVariant, { + id: "test-variant", + inventory_quantity: 10, + title: "Test variant", + variant_rank: 0, + sku: "test-sku", + ean: "test-ean", + upc: "test-upc", + barcode: "test-barcode", + product_id: "test-product", + prices: [{ id: "test-price", currency_code: "usd", amount: 100 }], + options: [ + { + id: "test-variant-option", + value: "Default variant", + option_id: "test-option", + }, + ], + }) + + await manager.save(variant1) + + const variant2 = await manager.create(ProductVariant, { + id: "test-variant_1", + inventory_quantity: 10, + title: "Test variant rank (1)", + variant_rank: 2, + sku: "test-sku1", + ean: "test-ean1", + upc: "test-upc1", + barcode: "test-barcode 1", + product_id: "test-product", + prices: [{ id: "test-price1", currency_code: "usd", amount: 100 }], + options: [ + { + id: "test-variant-option-1", + value: "Default variant 1", + option_id: "test-option", + }, + ], + }) + + await manager.save(variant2) + + const variant3 = await manager.create(ProductVariant, { + id: "test-variant_2", + inventory_quantity: 10, + title: "Test variant rank (2)", + variant_rank: 1, + sku: "test-sku2", + ean: "test-ean2", + upc: "test-upc2", + product_id: "test-product", + prices: [{ id: "test-price2", currency_code: "usd", amount: 100 }], + options: [ + { + id: "test-variant-option-2", + value: "Default variant 2", + option_id: "test-option", + }, + ], + }) + + await manager.save(variant3) + + const p1 = manager.create(Product, { + id: "test-product1", + handle: "test-product1", + title: "Test product1", + profile_id: defaultProfile.id, + description: "test-product-description1", + collection_id: "test-collection", + type: { id: "test-type", value: "test-type" }, + tags: [ + { id: "tag1", value: "123" }, + { tag: "tag2", value: "456" }, + ], + }) + + await manager.save(p1) + + const variant4 = await manager.create(ProductVariant, { + id: "test-variant_3", + inventory_quantity: 10, + title: "Test variant rank (2)", + variant_rank: 1, + sku: "test-sku3", + ean: "test-ean3", + upc: "test-upc3", + product_id: "test-product1", + prices: [{ id: "test-price3", currency_code: "usd", amount: 100 }], + options: [ + { + id: "test-variant-option-3", + value: "Default variant 3", + option_id: "test-option", + }, + ], + }) + + await manager.save(variant4) + + const variant5 = await manager.create(ProductVariant, { + id: "test-variant_4", + inventory_quantity: 10, + title: "Test variant rank (2)", + variant_rank: 0, + sku: "test-sku4", + ean: "test-ean4", + upc: "test-upc4", + product_id: "test-product1", + prices: [{ id: "test-price4", currency_code: "usd", amount: 100 }], + options: [ + { + id: "test-variant-option-4", + value: "Default variant 4", + option_id: "test-option", + }, + ], + }) + + await manager.save(variant5) + + const product1 = manager.create(Product, { + id: "test-product_filtering_1", + handle: "test-product_filtering_1", + title: "Test product filtering 1", + profile_id: defaultProfile.id, + description: "test-product-description", + type: { id: "test-type", value: "test-type" }, + collection_id: "test-collection1", + status: "proposed", + tags: [{ id: "tag3", value: "123" }], + }) + + await manager.save(product1) + + const product2 = manager.create(Product, { + id: "test-product_filtering_2", + handle: "test-product_filtering_2", + title: "Test product filtering 2", + profile_id: defaultProfile.id, + description: "test-product-description", + type: { id: "test-type", value: "test-type" }, + collection_id: "test-collection2", + status: "published", + tags: [{ id: "tag3", value: "123" }], + }) + + await manager.save(product2) + + const product3 = manager.create(Product, { + id: "test-product_filtering_3", + handle: "test-product_filtering_3", + title: "Test product filtering 3", + profile_id: defaultProfile.id, + description: "test-product-description", + type: { id: "test-type", value: "test-type" }, + collection_id: "test-collection1", + status: "draft", + tags: [{ id: "tag4", value: "1234" }], + }) + + await manager.save(product3) + + const product4 = manager.create(Product, { + id: "test-product_filtering_4", + handle: "test-product_filtering_4", + title: "Test product filtering 4", + profile_id: defaultProfile.id, + description: "test-product-description", + status: "proposed", + deleted_at: new Date().toISOString(), + }) + + await manager.save(product4) +} diff --git a/integration-tests/plugins/helpers/shipping-option-seeder.js b/integration-tests/plugins/helpers/shipping-option-seeder.js new file mode 100644 index 0000000000..33d669ca23 --- /dev/null +++ b/integration-tests/plugins/helpers/shipping-option-seeder.js @@ -0,0 +1,83 @@ +const { + Region, + ShippingProfile, + ShippingOption, + ShippingOptionRequirement, +} = require("@medusajs/medusa") + +module.exports = async (connection, data = {}) => { + const manager = connection.manager + + await manager.insert(Region, { + id: "region", + name: "Test Region", + currency_code: "usd", + tax_rate: 0, + }) + + const defaultProfile = await manager.findOne(ShippingProfile, { + type: "default", + }) + + await manager.insert(ShippingOption, { + id: "test-out", + name: "Test out", + profile_id: defaultProfile.id, + region_id: "region", + provider_id: "test-ful", + data: {}, + price_type: "flat_rate", + amount: 2000, + is_return: false, + }) + + await manager.insert(ShippingOption, { + id: "test-option-req", + name: "With req", + profile_id: defaultProfile.id, + region_id: "region", + provider_id: "test-ful", + data: {}, + price_type: "flat_rate", + amount: 2000, + is_return: false, + }) + + await manager.insert(ShippingOption, { + id: "test-option-req-admin-only", + name: "With req", + profile_id: defaultProfile.id, + region_id: "region", + admin_only: true, + provider_id: "test-ful", + data: {}, + price_type: "flat_rate", + amount: 2000, + is_return: false, + }) + await manager.insert(ShippingOption, { + id: "test-option-req-return", + name: "With req", + profile_id: defaultProfile.id, + region_id: "region", + is_return: true, + provider_id: "test-ful", + data: {}, + price_type: "flat_rate", + amount: 2000, + }) + + await manager.insert(ShippingOptionRequirement, { + id: "option-req", + shipping_option_id: "test-option-req", + type: "min_subtotal", + amount: 5, + }) + + await manager.insert(ShippingOptionRequirement, { + id: "option-req-2", + shipping_option_id: "test-option-req", + type: "max_subtotal", + amount: 10, + }) +} diff --git a/integration-tests/plugins/helpers/swap-seeder.js b/integration-tests/plugins/helpers/swap-seeder.js new file mode 100644 index 0000000000..233cf0177b --- /dev/null +++ b/integration-tests/plugins/helpers/swap-seeder.js @@ -0,0 +1,434 @@ +const { + Discount, + DiscountRule, + LineItem, + ShippingMethod, + Order, + Swap, + Cart, + Return, +} = require("@medusajs/medusa") +const { + CustomShippingOption, +} = require("@medusajs/medusa/dist/models/custom-shipping-option") + +module.exports = async (connection, data = {}) => { + const manager = connection.manager + + let orderWithSwap = manager.create(Order, { + id: "order-with-swap", + customer_id: "test-customer", + email: "test@email.com", + payment_status: "captured", + fulfillment_status: "fulfilled", + billing_address: { + id: "test-billing-address", + first_name: "lebron", + }, + shipping_address: { + id: "test-shipping-address", + first_name: "lebron", + country_code: "us", + }, + region_id: "test-region", + currency_code: "usd", + tax_rate: 0, + discounts: [], + payments: [ + { + id: "test-payment", + amount: 10000, + currency_code: "usd", + amount_refunded: 0, + provider_id: "test-pay", + data: {}, + }, + ], + items: [], + ...data, + }) + + orderWithSwap = await manager.save(orderWithSwap) + + const cart = manager.create(Cart, { + id: "test-cart-w-swap", + customer_id: "test-customer", + email: "test-customer@email.com", + shipping_address_id: "test-shipping-address", + billing_address_id: "test-billing-address", + region_id: "test-region", + type: "swap", + metadata: { + swap_id: "test-swap", + parent_order_id: orderWithSwap.id, + }, + }) + + await manager.save(cart) + + const swap = manager.create(Swap, { + id: "test-swap", + order_id: "order-with-swap", + payment_status: "captured", + fulfillment_status: "fulfilled", + cart_id: "test-cart-w-swap", + payment: { + id: "test-payment-swap", + amount: 10000, + currency_code: "usd", + amount_refunded: 0, + provider_id: "test-pay", + data: {}, + }, + additional_items: [ + { + id: "test-item-swapped", + fulfilled_quantity: 1, + title: "Line Item", + description: "Line Item Desc", + thumbnail: "https://test.js/1234", + unit_price: 9000, + quantity: 1, + variant_id: "test-variant-2", + cart_id: "test-cart-w-swap", + }, + ], + }) + + await manager.save(swap) + + const cartWithCustomSo = manager.create(Cart, { + id: "test-cart-rma", + customer_id: "test-customer", + email: "test-customer@email.com", + shipping_address_id: "test-shipping-address", + billing_address_id: "test-billing-address", + region_id: "test-region", + type: "swap", + metadata: { + swap_id: "test-swap", + parent_order_id: orderWithSwap.id, + }, + }) + + await manager.save(cartWithCustomSo) + + const liRma = manager.create(LineItem, { + id: "test-item-rma", + title: "Line Item RMA", + description: "Line Item Desc", + thumbnail: "https://test.js/1234", + unit_price: 8000, + quantity: 1, + variant_id: "test-variant", + cart_id: "test-cart-rma", + }) + await manager.save(liRma) + + manager.insert(CustomShippingOption, { + id: "cso-test", + cart_id: cartWithCustomSo.id, + price: 0, + shipping_option_id: "test-option", + }) + + const swapWithRMAMethod = manager.create(Swap, { + id: "test-swap-rma", + order_id: "order-with-swap", + payment_status: "captured", + fulfillment_status: "fulfilled", + cart_id: cartWithCustomSo.id, + payment: { + id: "test-payment-swap", + amount: 10000, + currency_code: "usd", + amount_refunded: 0, + provider_id: "test-pay", + data: {}, + }, + additional_items: [ + { + id: "test-item-swapped", + fulfilled_quantity: 1, + title: "Line Item", + description: "Line Item Desc", + thumbnail: "https://test.js/1234", + unit_price: 9000, + quantity: 1, + variant_id: "test-variant-2", + cart_id: "test-cart", + }, + ], + }) + + await manager.save(swapWithRMAMethod) + + const cartTemplate = async (cartId) => { + const cart = manager.create(Cart, { + id: cartId, + customer_id: "test-customer", + email: "test-customer@email.com", + shipping_address_id: "test-shipping-address", + billing_address_id: "test-billing-address", + region_id: "test-region", + type: "swap", + metadata: {}, + ...data, + }) + + await manager.save(cart) + } + + const swapTemplate = async (cartId) => { + await cartTemplate(cartId) + return { + order_id: orderWithSwap.id, + fulfillment_status: "fulfilled", + payment_status: "not_paid", + cart_id: cartId, + payment: { + amount: 5000, + currency_code: "usd", + amount_refunded: 0, + provider_id: "test-pay", + data: {}, + }, + ...data, + } + } + + const swapWithFulfillments = manager.create(Swap, { + id: "swap-w-f", + fulfillments: [ + { + id: "fulfillment-1", + data: {}, + provider_id: "test-ful", + }, + { + id: "fulfillment-2", + data: {}, + provider_id: "test-ful", + }, + ], + ...(await swapTemplate("sc-w-f")), + }) + + await manager.save(swapWithFulfillments) + + const swapWithReturn = manager.create(Swap, { + id: "swap-w-r", + return_order: { + id: "return-id", + status: "requested", + refund_amount: 0, + }, + ...(await swapTemplate("sc-w-r")), + }) + + await manager.save(swapWithReturn) + const li = manager.create(LineItem, { + id: "return-item-1", + fulfilled_quantity: 1, + title: "Return Line Item", + description: "Line Item Desc", + thumbnail: "https://test.js/1234", + unit_price: 8000, + quantity: 1, + variant_id: "test-variant", + order_id: orderWithSwap.id, + cart_id: cart.id, + }) + + await manager.save(li) + + const li2 = manager.create(LineItem, { + id: "test-item-many", + fulfilled_quantity: 4, + title: "Line Item", + description: "Line Item Desc", + thumbnail: "https://test.js/1234", + unit_price: 8000, + quantity: 4, + variant_id: "test-variant", + order_id: orderWithSwap.id, + }) + + await manager.save(li2) + + const swapReturn = await manager.create(Return, { + swap_id: swap.id, + order_id: orderWithSwap.id, + item_id: li.id, + refund_amount: li.quantity * li.unit_price, + }) + + await manager.save(swapReturn) + + const return_item1 = manager.create(LineItem, { + ...li, + unit_price: -1 * li.unit_price, + }) + + await manager.save(return_item1) + + await manager.insert(ShippingMethod, { + id: "another-test-method", + shipping_option_id: "test-option", + cart_id: "test-cart-w-swap", + price: 1000, + data: {}, + }) + + const swapOnSwap = manager.create(Swap, { + id: "swap-on-swap", + order_id: "order-with-swap", + payment_status: "captured", + fulfillment_status: "fulfilled", + return_order: { + id: "return-on-swap", + refund_amount: 9000, + items: [ + { + return_id: "return-on-swap", + item_id: "test-item-swapped", + quantity: 1, + }, + ], + }, + payment: { + id: "test-payment-swap-on-swap", + amount: 10000, + currency_code: "usd", + amount_refunded: 0, + provider_id: "test-pay", + data: {}, + }, + additional_items: [ + { + id: "test-item-swap-on-swap", + fulfilled_quantity: 1, + title: "Line Item", + description: "Line Item Desc", + thumbnail: "https://test.js/1234", + unit_price: 8000, + quantity: 1, + variant_id: "test-variant", + }, + ], + }) + + await manager.save(swapOnSwap) + + await manager.insert(ShippingMethod, { + id: "test-method-swap-order", + shipping_option_id: "test-option", + order_id: "order-with-swap", + price: 1000, + data: {}, + }) + + await createSwap({ id: "disc-swap" }, manager) +} + +const createSwap = async (options, manager) => { + const swapId = options.id + + const dRule = manager.create(DiscountRule, { + id: `${swapId}-cart-discount-rule`, + description: "Ten percent rule", + type: "percentage", + value: 10, + allocation: "total", + }) + await manager.save(dRule) + + const discount = manager.create(Discount, { + code: `${swapId}`, + is_dynamic: false, + is_disabled: false, + rule: dRule, + }) + await manager.save(discount) + + const cart = manager.create(Cart, { + id: `${swapId}-cart`, + customer_id: "test-customer", + email: "test-customer@email.com", + shipping_address_id: "test-shipping-address", + billing_address_id: "test-billing-address", + region_id: "test-region", + type: "swap", + discounts: [discount], + metadata: { + swap_id: swapId, + parent_order_id: "order-with-swap", + }, + }) + + await manager.save(cart) + + const swapTemplate = async () => { + return { + order_id: `order-with-swap`, + fulfillment_status: "fulfilled", + payment_status: "not_paid", + cart_id: cart.id, + } + } + + const swapWithReturn = manager.create(Swap, { + id: swapId, + return_order: { + id: `${swapId}-return-id`, + status: "requested", + refund_amount: 0, + }, + ...(await swapTemplate(swapId)), + }) + + await manager.save(swapWithReturn) + const li = manager.create(LineItem, { + id: `${swapId}-return-item-1`, + fulfilled_quantity: 1, + title: "Return Line Item", + description: "Line Item Desc", + thumbnail: "https://test.js/1234", + unit_price: 8000, + quantity: 1, + variant_id: "test-variant", + order_id: "order-with-swap", + cart_id: cart.id, + }) + + await manager.save(li) + + const li2 = manager.create(LineItem, { + id: `${swapId}-test-item-many`, + fulfilled_quantity: 4, + title: "Line Item", + description: "Line Item Desc", + thumbnail: "https://test.js/1234", + unit_price: 8000, + quantity: 4, + variant_id: "test-variant", + order_id: "order-with-swap", + }) + + await manager.save(li2) + + const return_item1 = manager.create(LineItem, { + ...li, + unit_price: -1 * li.unit_price, + }) + + await manager.save(return_item1) + + await manager.insert(ShippingMethod, { + id: `${swapId}-test-method`, + shipping_option_id: "test-option", + cart_id: cart.id, + price: 1000, + data: {}, + }) +} diff --git a/integration-tests/plugins/helpers/user-seeder.js b/integration-tests/plugins/helpers/user-seeder.js new file mode 100644 index 0000000000..bdea83131c --- /dev/null +++ b/integration-tests/plugins/helpers/user-seeder.js @@ -0,0 +1,53 @@ +const { User, Invite } = require("@medusajs/medusa") +import jwt from "jsonwebtoken" + +const generateToken = (data) => { + return jwt.sign(data, "test", { + expiresIn: "7d", + }) +} + +const expires_at = new Date() + +expires_at.setDate(expires_at.getDate() + 8) + +module.exports = async (connection, data = {}) => { + const manager = connection.manager + + const memberUser = await manager.create(User, { + id: "member-user", + role: "member", + email: "member@test.com", + first_name: "member", + last_name: "user", + }) + await manager.save(memberUser) + + const memberInvite = await manager.create(Invite, { + id: "memberInvite", + user_email: "invite-member@test.com", + role: "member", + token: generateToken({ + invite_id: "memberInvite", + role: "member", + user_email: "invite-member@test.com", + }), + accepted: false, + expires_at: expires_at, + }) + await manager.save(memberInvite) + + const adminInvite = await manager.create(Invite, { + id: "adminInvite", + user_email: "invite-admin@test.com", + role: "admin", + accepted: false, + token: generateToken({ + invite_id: "adminInvite", + role: "admin", + user_email: "invite-admin@test.com", + }), + expires_at: expires_at, + }) + await manager.save(adminInvite) +} diff --git a/integration-tests/plugins/jest.config.js b/integration-tests/plugins/jest.config.js new file mode 100644 index 0000000000..2fa84f26ed --- /dev/null +++ b/integration-tests/plugins/jest.config.js @@ -0,0 +1,19 @@ +// API + +module.exports = { + testEnvironment: `node`, + testPathIgnorePatterns: [ + `/examples/`, + `/www/`, + `/dist/`, + `/node_modules/`, + `__tests__/fixtures`, + `__testfixtures__`, + `.cache`, + ], + transformIgnorePatterns: [`/dist`], + transform: { "^.+\\.[jt]s$": `../../jest-transformer.js` }, + setupFilesAfterEnv: ["../setup.js"], + globalSetup: "../globalSetup.js", + globalTeardown: "../globalTeardown.js", +} diff --git a/integration-tests/plugins/medusa-config.js b/integration-tests/plugins/medusa-config.js new file mode 100644 index 0000000000..c4bab70d40 --- /dev/null +++ b/integration-tests/plugins/medusa-config.js @@ -0,0 +1,28 @@ +const DB_USERNAME = process.env.DB_USERNAME || "postgres" +const DB_PASSWORD = process.env.DB_PASSWORD || "" +const workerId = parseInt(process.env.JEST_WORKER_ID || "1") + +module.exports = { + plugins: [ + { + resolve: `medusa-fulfillment-webshipper`, + options: { + account: "test-account", + api_token: "something", + order_channel_id: "1", + webhook_secret: "1234", + }, + }, + { + resolve: `medusa-plugin-sendgrid`, + options: { + api_key: "SG.TEST", + }, + }, + ], + projectConfig: { + // redis_url: REDIS_URL, + database_url: `postgres://${DB_USERNAME}:${DB_PASSWORD}@localhost/medusa-integration-${workerId}`, + database_type: "postgres", + }, +} diff --git a/integration-tests/plugins/package.json b/integration-tests/plugins/package.json new file mode 100644 index 0000000000..05ca81ab27 --- /dev/null +++ b/integration-tests/plugins/package.json @@ -0,0 +1,25 @@ +{ + "name": "plugins", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "scripts": { + "test": "jest --maxWorkers=50% --silent=false", + "build": "babel src -d dist --extensions \".ts,.js\"" + }, + "dependencies": { + "@medusajs/medusa": "1.1.60-dev-1642337635041", + "faker": "^5.5.3", + "medusa-fulfillment-webshipper": "1.1.35-dev-1642337635041", + "medusa-interfaces": "1.1.32-dev-1642337635041", + "medusa-plugin-sendgrid": "1.1.36-dev-1642337635041", + "typeorm": "^0.2.31" + }, + "devDependencies": { + "@babel/cli": "^7.12.10", + "@babel/core": "^7.12.10", + "@babel/node": "^7.12.10", + "babel-preset-medusa-package": "1.1.19-dev-1642337635041", + "jest": "^26.6.3" + } +} diff --git a/integration-tests/plugins/src/services/test-ful.js b/integration-tests/plugins/src/services/test-ful.js new file mode 100644 index 0000000000..f7726108ac --- /dev/null +++ b/integration-tests/plugins/src/services/test-ful.js @@ -0,0 +1,53 @@ +import { FulfillmentService } from "medusa-interfaces" + +class TestFulService extends FulfillmentService { + static identifier = "test-ful" + + constructor() { + super() + } + + getFulfillmentOptions() { + return [ + { + id: "manual-fulfillment", + }, + ] + } + + validateFulfillmentData(data, cart) { + return data + } + + validateOption(data) { + return true + } + + canCalculate() { + return false + } + + calculatePrice() { + throw Error("Manual Fulfillment service cannot calculatePrice") + } + + createOrder() { + // No data is being sent anywhere + return Promise.resolve({}) + } + + createReturn() { + return Promise.resolve({}) + } + + createFulfillment() { + // No data is being sent anywhere + return Promise.resolve({}) + } + + cancelFulfillment() { + return Promise.resolve({}) + } +} + +export default TestFulService diff --git a/integration-tests/plugins/src/services/test-not.js b/integration-tests/plugins/src/services/test-not.js new file mode 100644 index 0000000000..39c5ba665a --- /dev/null +++ b/integration-tests/plugins/src/services/test-not.js @@ -0,0 +1,19 @@ +import { NotificationService } from "medusa-interfaces" + +class TestNotiService extends NotificationService { + static identifier = "test-not" + + constructor() { + super() + } + + async sendNotification() { + return Promise.resolve() + } + + async resendNotification() { + return Promise.resolve() + } +} + +export default TestNotiService diff --git a/integration-tests/plugins/src/services/test-pay.js b/integration-tests/plugins/src/services/test-pay.js new file mode 100644 index 0000000000..eed8aa80e5 --- /dev/null +++ b/integration-tests/plugins/src/services/test-pay.js @@ -0,0 +1,73 @@ +import { PaymentService } from "medusa-interfaces" + +class TestPayService extends PaymentService { + static identifier = "test-pay" + + constructor() { + super() + } + + async getStatus(paymentData) { + return "authorized" + } + + async retrieveSavedMethods(customer) { + return Promise.resolve([]) + } + + async createPayment(cart) { + const fields = [ + "total", + "subtotal", + "tax_total", + "discount_total", + "shipping_total", + "gift_card_total", + ] + + const data = {} + for (const k of fields) { + data[k] = cart[k] + } + + return data + } + + async retrievePayment(data) { + return {} + } + + async getPaymentData(sessionData) { + return {} + } + + async authorizePayment(sessionData, context = {}) { + return { data: {}, status: "authorized" } + } + + async updatePaymentData(sessionData, update) { + return {} + } + + async updatePayment(sessionData, cart) { + return {} + } + + async deletePayment(payment) { + return {} + } + + async capturePayment(payment) { + return {} + } + + async refundPayment(payment, amountToRefund) { + return {} + } + + async cancelPayment(payment) { + return {} + } +} + +export default TestPayService diff --git a/integration-tests/plugins/yarn.lock b/integration-tests/plugins/yarn.lock new file mode 100644 index 0000000000..f40c9eecd4 --- /dev/null +++ b/integration-tests/plugins/yarn.lock @@ -0,0 +1,7781 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/cli@^7.12.10": + version "7.16.8" + resolved "http://localhost:4873/@babel%2fcli/-/cli-7.16.8.tgz#44b9be7706762bfa3bff8adbf746da336eb0ab7c" + integrity sha512-FTKBbxyk5TclXOGmwYyqelqP5IF6hMxaeJskd85jbR5jBfYlwqgwAbJwnixi1ZBbTqKfFuAA95mdmUFeSRwyJA== + dependencies: + commander "^4.0.1" + convert-source-map "^1.1.0" + fs-readdir-recursive "^1.1.0" + glob "^7.0.0" + make-dir "^2.1.0" + slash "^2.0.0" + source-map "^0.5.0" + optionalDependencies: + "@nicolo-ribaudo/chokidar-2" "2.1.8-no-fsevents.3" + chokidar "^3.4.0" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fcode-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.4", "@babel/compat-data@^7.16.8": + version "7.16.8" + resolved "http://localhost:4873/@babel%2fcompat-data/-/compat-data-7.16.8.tgz#31560f9f29fdf1868de8cb55049538a1b9732a60" + integrity sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q== + +"@babel/core@^7.1.0", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.7.5": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fcore/-/core-7.16.7.tgz#db990f931f6d40cb9b87a0dc7d2adc749f1dcbcf" + integrity sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.16.7" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helpers" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + source-map "^0.5.0" + +"@babel/generator@^7.16.7", "@babel/generator@^7.16.8": + version "7.16.8" + resolved "http://localhost:4873/@babel%2fgenerator/-/generator-7.16.8.tgz#359d44d966b8cd059d543250ce79596f792f2ebe" + integrity sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw== + dependencies: + "@babel/types" "^7.16.8" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" + integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz#38d138561ea207f0f69eb1626a418e4f7e6a580b" + integrity sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz#06e66c5f299601e6c7da350049315e83209d551b" + integrity sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA== + dependencies: + "@babel/compat-data" "^7.16.4" + "@babel/helper-validator-option" "^7.16.7" + browserslist "^4.17.5" + semver "^6.3.0" + +"@babel/helper-create-class-features-plugin@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.7.tgz#9c5b34b53a01f2097daf10678d65135c1b9f84ba" + integrity sha512-kIFozAvVfK05DM4EVQYKK+zteWvY85BFdGBRQBytRyY3y+6PX0DkDOn/CZ3lEuczCfrCxEzwt0YtP/87YPTWSw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-member-expression-to-functions" "^7.16.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + +"@babel/helper-create-regexp-features-plugin@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.7.tgz#0cb82b9bac358eb73bfbd73985a776bfa6b14d48" + integrity sha512-fk5A6ymfp+O5+p2yCkXAu5Kyj6v0xh0RBeNcAkYUMDvvAAoxvSKXn+Jb37t/yWFiQVDFK1ELpUTD8/aLhCPu+g== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + regexpu-core "^4.7.1" + +"@babel/helper-define-polyfill-provider@^0.3.0": + version "0.3.0" + resolved "http://localhost:4873/@babel%2fhelper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.0.tgz#c5b10cf4b324ff840140bb07e05b8564af2ae971" + integrity sha512-7hfT8lUljl/tM3h+izTX/pO3W3frz2ok6Pk+gzys8iJqDfZrZy2pXjRTZAvG2YmfHun1X4q8/UZRLatMfqc5Tg== + dependencies: + "@babel/helper-compilation-targets" "^7.13.0" + "@babel/helper-module-imports" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/traverse" "^7.13.0" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + +"@babel/helper-environment-visitor@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" + integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-explode-assignable-expression@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz#12a6d8522fdd834f194e868af6354e8650242b7a" + integrity sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-function-name@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" + integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== + dependencies: + "@babel/helper-get-function-arity" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/helper-get-function-arity@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" + integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-hoist-variables@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" + integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-member-expression-to-functions@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz#42b9ca4b2b200123c3b7e726b0ae5153924905b0" + integrity sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" + integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-transforms@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-module-transforms/-/helper-module-transforms-7.16.7.tgz#7665faeb721a01ca5327ddc6bba15a5cb34b6a41" + integrity sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng== + dependencies: + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-simple-access" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/helper-optimise-call-expression@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz#a34e3560605abbd31a18546bd2aad3e6d9a174f2" + integrity sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" + integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== + +"@babel/helper-remap-async-to-generator@^7.16.8": + version "7.16.8" + resolved "http://localhost:4873/@babel%2fhelper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz#29ffaade68a367e2ed09c90901986918d25e57e3" + integrity sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-wrap-function" "^7.16.8" + "@babel/types" "^7.16.8" + +"@babel/helper-replace-supers@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-replace-supers/-/helper-replace-supers-7.16.7.tgz#e9f5f5f32ac90429c1a4bdec0f231ef0c2838ab1" + integrity sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw== + dependencies: + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-member-expression-to-functions" "^7.16.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/helper-simple-access@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-simple-access/-/helper-simple-access-7.16.7.tgz#d656654b9ea08dbb9659b69d61063ccd343ff0f7" + integrity sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-skip-transparent-expression-wrappers@^7.16.0": + version "7.16.0" + resolved "http://localhost:4873/@babel%2fhelper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" + integrity sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw== + dependencies: + "@babel/types" "^7.16.0" + +"@babel/helper-split-export-declaration@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" + integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + +"@babel/helper-validator-option@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" + integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== + +"@babel/helper-wrap-function@^7.16.8": + version "7.16.8" + resolved "http://localhost:4873/@babel%2fhelper-wrap-function/-/helper-wrap-function-7.16.8.tgz#58afda087c4cd235de92f7ceedebca2c41274200" + integrity sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw== + dependencies: + "@babel/helper-function-name" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.8" + "@babel/types" "^7.16.8" + +"@babel/helpers@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhelpers/-/helpers-7.16.7.tgz#7e3504d708d50344112767c3542fc5e357fffefc" + integrity sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw== + dependencies: + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/highlight@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fhighlight/-/highlight-7.16.7.tgz#81a01d7d675046f0d96f82450d9d9578bdfd6b0b" + integrity sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/node@^7.12.10": + version "7.16.8" + resolved "http://localhost:4873/@babel%2fnode/-/node-7.16.8.tgz#57ba1dfa63dbcc72d477f05597ce07f1c4f8b558" + integrity sha512-V2dopEtPUL4LD+e8UtMIZB6BbsmMsS/7E1ZAvWNINzBfi7Cf3X9MLCpzHVZT4HeeF1lQl72IRtqqVt2RUImwyA== + dependencies: + "@babel/register" "^7.16.8" + commander "^4.0.1" + core-js "^3.20.2" + node-environment-flags "^1.0.5" + regenerator-runtime "^0.13.4" + v8flags "^3.1.1" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.16.8": + version "7.16.8" + resolved "http://localhost:4873/@babel%2fparser/-/parser-7.16.8.tgz#61c243a3875f7d0b0962b0543a33ece6ff2f1f17" + integrity sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw== + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz#4eda6d6c2a0aa79c70fa7b6da67763dfe2141050" + integrity sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz#cc001234dfc139ac45f6bcf801866198c8c72ff9" + integrity sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-proposal-optional-chaining" "^7.16.7" + +"@babel/plugin-proposal-async-generator-functions@^7.16.8": + version "7.16.8" + resolved "http://localhost:4873/@babel%2fplugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz#3bdd1ebbe620804ea9416706cd67d60787504bc8" + integrity sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-remap-async-to-generator" "^7.16.8" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-proposal-class-properties@^7.12.1", "@babel/plugin-proposal-class-properties@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz#925cad7b3b1a2fcea7e59ecc8eb5954f961f91b0" + integrity sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-proposal-class-static-block@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.7.tgz#712357570b612106ef5426d13dc433ce0f200c2a" + integrity sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-proposal-decorators@^7.12.1": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-proposal-decorators/-/plugin-proposal-decorators-7.16.7.tgz#922907d2e3e327f5b07d2246bcfc0bd438f360d2" + integrity sha512-DoEpnuXK14XV9btI1k8tzNGCutMclpj4yru8aXKoHlVmbO1s+2A+g2+h4JhcjrxkFJqzbymnLG6j/niOf3iFXQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-decorators" "^7.16.7" + +"@babel/plugin-proposal-dynamic-import@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz#c19c897eaa46b27634a00fee9fb7d829158704b2" + integrity sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-proposal-export-namespace-from@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz#09de09df18445a5786a305681423ae63507a6163" + integrity sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz#9732cb1d17d9a2626a08c5be25186c195b6fa6e8" + integrity sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-proposal-logical-assignment-operators@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz#be23c0ba74deec1922e639832904be0bea73cdea" + integrity sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz#141fc20b6857e59459d430c850a0011e36561d99" + integrity sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-proposal-numeric-separator@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz#d6b69f4af63fb38b6ca2558442a7fb191236eba9" + integrity sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.7.tgz#94593ef1ddf37021a25bdcb5754c4a8d534b01d8" + integrity sha512-3O0Y4+dw94HA86qSg9IHfyPktgR7q3gpNVAeiKQd+8jBKFaU5NQS1Yatgo4wY+UFNuLjvxcSmzcsHqrhgTyBUA== + dependencies: + "@babel/compat-data" "^7.16.4" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.16.7" + +"@babel/plugin-proposal-optional-catch-binding@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz#c623a430674ffc4ab732fd0a0ae7722b67cb74cf" + integrity sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-proposal-optional-chaining@^7.14.2", "@babel/plugin-proposal-optional-chaining@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz#7cd629564724816c0e8a969535551f943c64c39a" + integrity sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-proposal-private-methods@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.7.tgz#e418e3aa6f86edd6d327ce84eff188e479f571e0" + integrity sha512-7twV3pzhrRxSwHeIvFE6coPgvo+exNDOiGUMg39o2LiLo1Y+4aKpfkcLGcg1UHonzorCt7SNXnoMyCnnIOA8Sw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-proposal-private-property-in-object@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz#b0b8cef543c2c3d57e59e2c611994861d46a3fce" + integrity sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-proposal-unicode-property-regex@^7.16.7", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz#635d18eb10c6214210ffc5ff4932552de08188a2" + integrity sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "http://localhost:4873/@babel%2fplugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "http://localhost:4873/@babel%2fplugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "http://localhost:4873/@babel%2fplugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "http://localhost:4873/@babel%2fplugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-decorators@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-syntax-decorators/-/plugin-syntax-decorators-7.16.7.tgz#f66a0199f16de7c1ef5192160ccf5d069739e3d3" + integrity sha512-vQ+PxL+srA7g6Rx6I1e15m55gftknl2X8GCUW1JTlkTaXZLJOS0UcaY0eK9jYT7IYf4awn6qwyghVHLDz1WyMw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "http://localhost:4873/@babel%2fplugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "http://localhost:4873/@babel%2fplugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "http://localhost:4873/@babel%2fplugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "http://localhost:4873/@babel%2fplugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "http://localhost:4873/@babel%2fplugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "http://localhost:4873/@babel%2fplugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "http://localhost:4873/@babel%2fplugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "http://localhost:4873/@babel%2fplugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "http://localhost:4873/@babel%2fplugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "http://localhost:4873/@babel%2fplugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "http://localhost:4873/@babel%2fplugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "http://localhost:4873/@babel%2fplugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz#39c9b55ee153151990fb038651d58d3fd03f98f8" + integrity sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-arrow-functions@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz#44125e653d94b98db76369de9c396dc14bef4154" + integrity sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-async-to-generator@^7.16.8": + version "7.16.8" + resolved "http://localhost:4873/@babel%2fplugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz#b83dff4b970cf41f1b819f8b49cc0cfbaa53a808" + integrity sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-remap-async-to-generator" "^7.16.8" + +"@babel/plugin-transform-block-scoped-functions@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz#4d0d57d9632ef6062cdf354bb717102ee042a620" + integrity sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-block-scoping@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz#f50664ab99ddeaee5bc681b8f3a6ea9d72ab4f87" + integrity sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-classes@^7.12.1", "@babel/plugin-transform-classes@^7.16.7", "@babel/plugin-transform-classes@^7.9.5": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz#8f4b9562850cd973de3b498f1218796eb181ce00" + integrity sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz#66dee12e46f61d2aae7a73710f591eb3df616470" + integrity sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-destructuring@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-destructuring/-/plugin-transform-destructuring-7.16.7.tgz#ca9588ae2d63978a4c29d3f33282d8603f618e23" + integrity sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-dotall-regex@^7.16.7", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz#6b2d67686fab15fb6a7fd4bd895d5982cfc81241" + integrity sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-duplicate-keys@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz#2207e9ca8f82a0d36a5a67b6536e7ef8b08823c9" + integrity sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-exponentiation-operator@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz#efa9862ef97e9e9e5f653f6ddc7b665e8536fe9b" + integrity sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-for-of@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz#649d639d4617dff502a9a158c479b3b556728d8c" + integrity sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-function-name@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz#5ab34375c64d61d083d7d2f05c38d90b97ec65cf" + integrity sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA== + dependencies: + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-instanceof@^7.12.1": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-instanceof/-/plugin-transform-instanceof-7.16.7.tgz#cedb7fb33e9fa25ace9cc2b020d2bb07bc584f11" + integrity sha512-DhH2rWEmDc+i9v3sVa4VIIFyKlMu3jPuJdwrq2Xcv9B+PxGkhdpyyNLJiBzZMyf3VVNN/voti03KY+C8lPh+Nw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-literals@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz#254c9618c5ff749e87cb0c0cef1a0a050c0bdab1" + integrity sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-member-expression-literals@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz#6e5dcf906ef8a098e630149d14c867dd28f92384" + integrity sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-modules-amd@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz#b28d323016a7daaae8609781d1f8c9da42b13186" + integrity sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g== + dependencies: + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-commonjs@^7.16.8": + version "7.16.8" + resolved "http://localhost:4873/@babel%2fplugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz#cdee19aae887b16b9d331009aa9a219af7c86afe" + integrity sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA== + dependencies: + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-simple-access" "^7.16.7" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-systemjs@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz#887cefaef88e684d29558c2b13ee0563e287c2d7" + integrity sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw== + dependencies: + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-umd@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz#23dad479fa585283dbd22215bff12719171e7618" + integrity sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ== + dependencies: + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.16.8": + version "7.16.8" + resolved "http://localhost:4873/@babel%2fplugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz#7f860e0e40d844a02c9dcf9d84965e7dfd666252" + integrity sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + +"@babel/plugin-transform-new-target@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz#9967d89a5c243818e0800fdad89db22c5f514244" + integrity sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-object-super@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz#ac359cf8d32cf4354d27a46867999490b6c32a94" + integrity sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + +"@babel/plugin-transform-parameters@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz#a1721f55b99b736511cb7e0152f61f17688f331f" + integrity sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-property-literals@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz#2dadac85155436f22c696c4827730e0fe1057a55" + integrity sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-regenerator@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz#9e7576dc476cb89ccc5096fff7af659243b4adeb" + integrity sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q== + dependencies: + regenerator-transform "^0.14.2" + +"@babel/plugin-transform-reserved-words@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz#1d798e078f7c5958eec952059c460b220a63f586" + integrity sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-runtime@^7.12.1": + version "7.16.8" + resolved "http://localhost:4873/@babel%2fplugin-transform-runtime/-/plugin-transform-runtime-7.16.8.tgz#3339368701103edae708f0fba9e4bfb70a3e5872" + integrity sha512-6Kg2XHPFnIarNweZxmzbgYnnWsXxkx9WQUVk2sksBRL80lBC1RAQV3wQagWxdCHiYHqPN+oenwNIuttlYgIbQQ== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + babel-plugin-polyfill-corejs2 "^0.3.0" + babel-plugin-polyfill-corejs3 "^0.5.0" + babel-plugin-polyfill-regenerator "^0.3.0" + semver "^6.3.0" + +"@babel/plugin-transform-shorthand-properties@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz#e8549ae4afcf8382f711794c0c7b6b934c5fbd2a" + integrity sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-spread@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz#a303e2122f9f12e0105daeedd0f30fb197d8ff44" + integrity sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + +"@babel/plugin-transform-sticky-regex@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz#c84741d4f4a38072b9a1e2e3fd56d359552e8660" + integrity sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-template-literals@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz#f3d1c45d28967c8e80f53666fc9c3e50618217ab" + integrity sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-typeof-symbol@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz#9cdbe622582c21368bd482b660ba87d5545d4f7e" + integrity sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-typescript@^7.16.7": + version "7.16.8" + resolved "http://localhost:4873/@babel%2fplugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz#591ce9b6b83504903fa9dd3652c357c2ba7a1ee0" + integrity sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-typescript" "^7.16.7" + +"@babel/plugin-transform-unicode-escapes@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz#da8717de7b3287a2c6d659750c964f302b31ece3" + integrity sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-unicode-regex@^7.16.7": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fplugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz#0f7aa4a501198976e25e82702574c34cfebe9ef2" + integrity sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/polyfill@^7.8.7": + version "7.12.1" + resolved "http://localhost:4873/@babel%2fpolyfill/-/polyfill-7.12.1.tgz#1f2d6371d1261bbd961f3c5d5909150e12d0bd96" + integrity sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g== + dependencies: + core-js "^2.6.5" + regenerator-runtime "^0.13.4" + +"@babel/preset-env@^7.12.7": + version "7.16.8" + resolved "http://localhost:4873/@babel%2fpreset-env/-/preset-env-7.16.8.tgz#e682fa0bcd1cf49621d64a8956318ddfb9a05af9" + integrity sha512-9rNKgVCdwHb3z1IlbMyft6yIXIeP3xz6vWvGaLHrJThuEIqWfHb0DNBH9VuTgnDfdbUDhkmkvMZS/YMCtP7Elg== + dependencies: + "@babel/compat-data" "^7.16.8" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-option" "^7.16.7" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.16.7" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.16.7" + "@babel/plugin-proposal-async-generator-functions" "^7.16.8" + "@babel/plugin-proposal-class-properties" "^7.16.7" + "@babel/plugin-proposal-class-static-block" "^7.16.7" + "@babel/plugin-proposal-dynamic-import" "^7.16.7" + "@babel/plugin-proposal-export-namespace-from" "^7.16.7" + "@babel/plugin-proposal-json-strings" "^7.16.7" + "@babel/plugin-proposal-logical-assignment-operators" "^7.16.7" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.7" + "@babel/plugin-proposal-numeric-separator" "^7.16.7" + "@babel/plugin-proposal-object-rest-spread" "^7.16.7" + "@babel/plugin-proposal-optional-catch-binding" "^7.16.7" + "@babel/plugin-proposal-optional-chaining" "^7.16.7" + "@babel/plugin-proposal-private-methods" "^7.16.7" + "@babel/plugin-proposal-private-property-in-object" "^7.16.7" + "@babel/plugin-proposal-unicode-property-regex" "^7.16.7" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-transform-arrow-functions" "^7.16.7" + "@babel/plugin-transform-async-to-generator" "^7.16.8" + "@babel/plugin-transform-block-scoped-functions" "^7.16.7" + "@babel/plugin-transform-block-scoping" "^7.16.7" + "@babel/plugin-transform-classes" "^7.16.7" + "@babel/plugin-transform-computed-properties" "^7.16.7" + "@babel/plugin-transform-destructuring" "^7.16.7" + "@babel/plugin-transform-dotall-regex" "^7.16.7" + "@babel/plugin-transform-duplicate-keys" "^7.16.7" + "@babel/plugin-transform-exponentiation-operator" "^7.16.7" + "@babel/plugin-transform-for-of" "^7.16.7" + "@babel/plugin-transform-function-name" "^7.16.7" + "@babel/plugin-transform-literals" "^7.16.7" + "@babel/plugin-transform-member-expression-literals" "^7.16.7" + "@babel/plugin-transform-modules-amd" "^7.16.7" + "@babel/plugin-transform-modules-commonjs" "^7.16.8" + "@babel/plugin-transform-modules-systemjs" "^7.16.7" + "@babel/plugin-transform-modules-umd" "^7.16.7" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.16.8" + "@babel/plugin-transform-new-target" "^7.16.7" + "@babel/plugin-transform-object-super" "^7.16.7" + "@babel/plugin-transform-parameters" "^7.16.7" + "@babel/plugin-transform-property-literals" "^7.16.7" + "@babel/plugin-transform-regenerator" "^7.16.7" + "@babel/plugin-transform-reserved-words" "^7.16.7" + "@babel/plugin-transform-shorthand-properties" "^7.16.7" + "@babel/plugin-transform-spread" "^7.16.7" + "@babel/plugin-transform-sticky-regex" "^7.16.7" + "@babel/plugin-transform-template-literals" "^7.16.7" + "@babel/plugin-transform-typeof-symbol" "^7.16.7" + "@babel/plugin-transform-unicode-escapes" "^7.16.7" + "@babel/plugin-transform-unicode-regex" "^7.16.7" + "@babel/preset-modules" "^0.1.5" + "@babel/types" "^7.16.8" + babel-plugin-polyfill-corejs2 "^0.3.0" + babel-plugin-polyfill-corejs3 "^0.5.0" + babel-plugin-polyfill-regenerator "^0.3.0" + core-js-compat "^3.20.2" + semver "^6.3.0" + +"@babel/preset-modules@^0.1.5": + version "0.1.5" + resolved "http://localhost:4873/@babel%2fpreset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" + integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/preset-typescript@^7.16.0": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fpreset-typescript/-/preset-typescript-7.16.7.tgz#ab114d68bb2020afc069cd51b37ff98a046a70b9" + integrity sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-option" "^7.16.7" + "@babel/plugin-transform-typescript" "^7.16.7" + +"@babel/register@^7.16.8": + version "7.16.8" + resolved "http://localhost:4873/@babel%2fregister/-/register-7.16.8.tgz#bb688b9dc127d98bb54e37e1d817aed1165833b8" + integrity sha512-aoUj2ocH92k7qyyA59y07sUaCVxxS7VjNul/jR0mpAyYvpo6n5HELZmyUGtrgFm7/1b0UutT7I1w/4bAkXxCHA== + dependencies: + clone-deep "^4.0.1" + find-cache-dir "^2.0.0" + make-dir "^2.1.0" + pirates "^4.0.0" + source-map-support "^0.5.16" + +"@babel/runtime@^7.15.4", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.6": + version "7.16.7" + resolved "http://localhost:4873/@babel%2fruntime/-/runtime-7.16.7.tgz#03ff99f64106588c9c403c6ecb8c3bafbbdff1fa" + integrity sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.16.7", "@babel/template@^7.3.3": + version "7.16.7" + resolved "http://localhost:4873/@babel%2ftemplate/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8": + version "7.16.8" + resolved "http://localhost:4873/@babel%2ftraverse/-/traverse-7.16.8.tgz#bab2f2b09a5fe8a8d9cad22cbfe3ba1d126fef9c" + integrity sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.16.8" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/parser" "^7.16.8" + "@babel/types" "^7.16.8" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": + version "7.16.8" + resolved "http://localhost:4873/@babel%2ftypes/-/types-7.16.8.tgz#0ba5da91dd71e0a4e7781a30f22770831062e3c1" + integrity sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "http://localhost:4873/@bcoe%2fv8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@cnakazawa/watch@^1.0.3": + version "1.0.4" + resolved "http://localhost:4873/@cnakazawa%2fwatch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" + integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== + dependencies: + exec-sh "^0.3.2" + minimist "^1.2.0" + +"@dabh/diagnostics@^2.0.2": + version "2.0.2" + resolved "http://localhost:4873/@dabh%2fdiagnostics/-/diagnostics-2.0.2.tgz#290d08f7b381b8f94607dc8f471a12c675f9db31" + integrity sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q== + dependencies: + colorspace "1.1.x" + enabled "2.0.x" + kuler "^2.0.0" + +"@hapi/address@^2.1.2": + version "2.1.4" + resolved "http://localhost:4873/@hapi%2faddress/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" + integrity sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ== + +"@hapi/formula@^1.2.0": + version "1.2.0" + resolved "http://localhost:4873/@hapi%2fformula/-/formula-1.2.0.tgz#994649c7fea1a90b91a0a1e6d983523f680e10cd" + integrity sha512-UFbtbGPjstz0eWHb+ga/GM3Z9EzqKXFWIbSOFURU0A/Gku0Bky4bCk9/h//K2Xr3IrCfjFNhMm4jyZ5dbCewGA== + +"@hapi/hoek@^8.2.4", "@hapi/hoek@^8.3.0": + version "8.5.1" + resolved "http://localhost:4873/@hapi%2fhoek/-/hoek-8.5.1.tgz#fde96064ca446dec8c55a8c2f130957b070c6e06" + integrity sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow== + +"@hapi/hoek@^9.0.0": + version "9.2.1" + resolved "http://localhost:4873/@hapi%2fhoek/-/hoek-9.2.1.tgz#9551142a1980503752536b5050fd99f4a7f13b17" + integrity sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw== + +"@hapi/joi@^16.1.8": + version "16.1.8" + resolved "http://localhost:4873/@hapi%2fjoi/-/joi-16.1.8.tgz#84c1f126269489871ad4e2decc786e0adef06839" + integrity sha512-wAsVvTPe+FwSrsAurNt5vkg3zo+TblvC5Bb1zMVK6SJzZqw9UrJnexxR+76cpePmtUZKHAPxcQ2Bf7oVHyahhg== + dependencies: + "@hapi/address" "^2.1.2" + "@hapi/formula" "^1.2.0" + "@hapi/hoek" "^8.2.4" + "@hapi/pinpoint" "^1.0.2" + "@hapi/topo" "^3.1.3" + +"@hapi/pinpoint@^1.0.2": + version "1.0.2" + resolved "http://localhost:4873/@hapi%2fpinpoint/-/pinpoint-1.0.2.tgz#025b7a36dbbf4d35bf1acd071c26b20ef41e0d13" + integrity sha512-dtXC/WkZBfC5vxscazuiJ6iq4j9oNx1SHknmIr8hofarpKUZKmlUVYVIhNVzIEgK5Wrc4GMHL5lZtt1uS2flmQ== + +"@hapi/topo@^3.1.3": + version "3.1.6" + resolved "http://localhost:4873/@hapi%2ftopo/-/topo-3.1.6.tgz#68d935fa3eae7fdd5ab0d7f953f3205d8b2bfc29" + integrity sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ== + dependencies: + "@hapi/hoek" "^8.3.0" + +"@hapi/topo@^5.0.0": + version "5.1.0" + resolved "http://localhost:4873/@hapi%2ftopo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012" + integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "http://localhost:4873/@istanbuljs%2fload-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "http://localhost:4873/@istanbuljs%2fschema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^26.6.2": + version "26.6.2" + resolved "http://localhost:4873/@jest%2fconsole/-/console-26.6.2.tgz#4e04bc464014358b03ab4937805ee36a0aeb98f2" + integrity sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g== + dependencies: + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^26.6.2" + jest-util "^26.6.2" + slash "^3.0.0" + +"@jest/core@^26.6.3": + version "26.6.3" + resolved "http://localhost:4873/@jest%2fcore/-/core-26.6.3.tgz#7639fcb3833d748a4656ada54bde193051e45fad" + integrity sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw== + dependencies: + "@jest/console" "^26.6.2" + "@jest/reporters" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-changed-files "^26.6.2" + jest-config "^26.6.3" + jest-haste-map "^26.6.2" + jest-message-util "^26.6.2" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-resolve-dependencies "^26.6.3" + jest-runner "^26.6.3" + jest-runtime "^26.6.3" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" + jest-watcher "^26.6.2" + micromatch "^4.0.2" + p-each-series "^2.1.0" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^26.6.2": + version "26.6.2" + resolved "http://localhost:4873/@jest%2fenvironment/-/environment-26.6.2.tgz#ba364cc72e221e79cc8f0a99555bf5d7577cf92c" + integrity sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA== + dependencies: + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + +"@jest/fake-timers@^26.6.2": + version "26.6.2" + resolved "http://localhost:4873/@jest%2ffake-timers/-/fake-timers-26.6.2.tgz#459c329bcf70cee4af4d7e3f3e67848123535aad" + integrity sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA== + dependencies: + "@jest/types" "^26.6.2" + "@sinonjs/fake-timers" "^6.0.1" + "@types/node" "*" + jest-message-util "^26.6.2" + jest-mock "^26.6.2" + jest-util "^26.6.2" + +"@jest/globals@^26.6.2": + version "26.6.2" + resolved "http://localhost:4873/@jest%2fglobals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a" + integrity sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA== + dependencies: + "@jest/environment" "^26.6.2" + "@jest/types" "^26.6.2" + expect "^26.6.2" + +"@jest/reporters@^26.6.2": + version "26.6.2" + resolved "http://localhost:4873/@jest%2freporters/-/reporters-26.6.2.tgz#1f518b99637a5f18307bd3ecf9275f6882a667f6" + integrity sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.2.4" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^4.0.3" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.0.2" + jest-haste-map "^26.6.2" + jest-resolve "^26.6.2" + jest-util "^26.6.2" + jest-worker "^26.6.2" + slash "^3.0.0" + source-map "^0.6.0" + string-length "^4.0.1" + terminal-link "^2.0.0" + v8-to-istanbul "^7.0.0" + optionalDependencies: + node-notifier "^8.0.0" + +"@jest/source-map@^26.6.2": + version "26.6.2" + resolved "http://localhost:4873/@jest%2fsource-map/-/source-map-26.6.2.tgz#29af5e1e2e324cafccc936f218309f54ab69d535" + integrity sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.2.4" + source-map "^0.6.0" + +"@jest/test-result@^26.6.2": + version "26.6.2" + resolved "http://localhost:4873/@jest%2ftest-result/-/test-result-26.6.2.tgz#55da58b62df134576cc95476efa5f7949e3f5f18" + integrity sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ== + dependencies: + "@jest/console" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^26.6.3": + version "26.6.3" + resolved "http://localhost:4873/@jest%2ftest-sequencer/-/test-sequencer-26.6.3.tgz#98e8a45100863886d074205e8ffdc5a7eb582b17" + integrity sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw== + dependencies: + "@jest/test-result" "^26.6.2" + graceful-fs "^4.2.4" + jest-haste-map "^26.6.2" + jest-runner "^26.6.3" + jest-runtime "^26.6.3" + +"@jest/transform@^26.6.2": + version "26.6.2" + resolved "http://localhost:4873/@jest%2ftransform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" + integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^26.6.2" + babel-plugin-istanbul "^6.0.0" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.4" + jest-haste-map "^26.6.2" + jest-regex-util "^26.0.0" + jest-util "^26.6.2" + micromatch "^4.0.2" + pirates "^4.0.1" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + +"@jest/types@^26.6.2": + version "26.6.2" + resolved "http://localhost:4873/@jest%2ftypes/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" + integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^15.0.0" + chalk "^4.0.0" + +"@medusajs/medusa-cli@1.1.25-dev-1642337635041": + version "1.1.25-dev-1642337635041" + resolved "http://localhost:4873/@medusajs%2fmedusa-cli/-/medusa-cli-1.1.25-dev-1642337635041.tgz#e3ca33f453446dddc4922f42b4254995de9874b5" + integrity sha512-8pA5iBMglgrdPRSEZLvjovJczib5zk9qlQJsewlSrw/aolwnusukEE7vBfjAiUXAZKngMx6BnYoORlWSV88wdA== + dependencies: + "@babel/polyfill" "^7.8.7" + "@babel/runtime" "^7.9.6" + "@hapi/joi" "^16.1.8" + axios "^0.21.1" + chalk "^4.0.0" + configstore "5.0.1" + core-js "^3.6.5" + dotenv "^8.2.0" + execa "^5.1.1" + fs-exists-cached "^1.0.0" + fs-extra "^10.0.0" + hosted-git-info "^4.0.2" + inquirer "^8.0.0" + is-valid-path "^0.1.1" + joi-objectid "^3.0.1" + meant "^1.0.1" + medusa-core-utils "1.1.31-dev-1642337635041" + medusa-telemetry "0.0.11-dev-1642337635041" + netrc-parser "^3.1.6" + open "^8.0.6" + ora "^5.4.1" + pg-god "^1.0.11" + prompts "^2.4.1" + regenerator-runtime "^0.13.5" + resolve-cwd "^3.0.0" + stack-trace "^0.0.10" + ulid "^2.3.0" + url "^0.11.0" + winston "^3.3.3" + yargs "^15.3.1" + +"@medusajs/medusa@1.1.60-dev-1642337635041": + version "1.1.60-dev-1642337635041" + resolved "http://localhost:4873/@medusajs%2fmedusa/-/medusa-1.1.60-dev-1642337635041.tgz#011d64b9b85a3f66e01f3755788370aa444a2e27" + integrity sha512-MBef46mJZMSyE3+dcijMqjFZbNo7AL60mP/PwkOy4W1d/t2MZ+GOBIufLAVxVw7SaiSjAGpQDmCrUOqQrIhIdg== + dependencies: + "@hapi/joi" "^16.1.8" + "@medusajs/medusa-cli" "1.1.25-dev-1642337635041" + "@types/lodash" "^4.14.168" + awilix "^4.2.3" + body-parser "^1.19.0" + bull "^3.12.1" + chokidar "^3.4.2" + class-transformer "^0.5.1" + class-validator "^0.13.1" + connect-redis "^5.0.0" + cookie-parser "^1.4.4" + core-js "^3.6.5" + cors "^2.8.5" + cross-spawn "^7.0.3" + dotenv "^8.2.0" + express "^4.17.1" + express-session "^1.17.1" + fs-exists-cached "^1.0.0" + glob "^7.1.6" + ioredis "^4.17.3" + ioredis-mock "^5.6.0" + iso8601-duration "^1.3.0" + joi "^17.3.0" + joi-objectid "^3.0.1" + jsonwebtoken "^8.5.1" + medusa-core-utils "1.1.31-dev-1642337635041" + medusa-test-utils "1.1.35-dev-1642337635041" + morgan "^1.9.1" + multer "^1.4.2" + passport "^0.4.0" + passport-http-bearer "^1.0.1" + passport-jwt "^4.0.0" + passport-local "^1.0.0" + pg "^8.5.1" + randomatic "^3.1.1" + redis "^3.0.2" + reflect-metadata "^0.1.13" + request-ip "^2.1.3" + resolve-cwd "^3.0.0" + scrypt-kdf "^2.0.1" + sqlite3 "^5.0.2" + ulid "^2.3.0" + uuid "^8.3.1" + winston "^3.2.1" + +"@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": + version "2.1.8-no-fsevents.3" + resolved "http://localhost:4873/@nicolo-ribaudo%2fchokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b" + integrity sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "http://localhost:4873/@nodelib%2ffs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "http://localhost:4873/@nodelib%2ffs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "http://localhost:4873/@nodelib%2ffs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@oclif/command@^1", "@oclif/command@^1.8.15": + version "1.8.16" + resolved "http://localhost:4873/@oclif%2fcommand/-/command-1.8.16.tgz#bea46f81b2061b47e1cda318a0b923e62ca4cc0c" + integrity sha512-rmVKYEsKzurfRU0xJz+iHelbi1LGlihIWZ7Qvmb/CBz1EkhL7nOkW4SVXmG2dA5Ce0si2gr88i6q4eBOMRNJ1w== + dependencies: + "@oclif/config" "^1.18.2" + "@oclif/errors" "^1.3.5" + "@oclif/help" "^1.0.1" + "@oclif/parser" "^3.8.6" + debug "^4.1.1" + semver "^7.3.2" + +"@oclif/config@1.18.2", "@oclif/config@^1", "@oclif/config@^1.18.2": + version "1.18.2" + resolved "http://localhost:4873/@oclif%2fconfig/-/config-1.18.2.tgz#5bfe74a9ba6a8ca3dceb314a81bd9ce2e15ebbfe" + integrity sha512-cE3qfHWv8hGRCP31j7fIS7BfCflm/BNZ2HNqHexH+fDrdF2f1D5S8VmXWLC77ffv3oDvWyvE9AZeR0RfmHCCaA== + dependencies: + "@oclif/errors" "^1.3.3" + "@oclif/parser" "^3.8.0" + debug "^4.1.1" + globby "^11.0.1" + is-wsl "^2.1.1" + tslib "^2.0.0" + +"@oclif/errors@1.3.5", "@oclif/errors@^1.2.2", "@oclif/errors@^1.3.3", "@oclif/errors@^1.3.5": + version "1.3.5" + resolved "http://localhost:4873/@oclif%2ferrors/-/errors-1.3.5.tgz#a1e9694dbeccab10fe2fe15acb7113991bed636c" + integrity sha512-OivucXPH/eLLlOT7FkCMoZXiaVYf8I/w1eTAM1+gKzfhALwWTusxEx7wBmW0uzvkSg/9ovWLycPaBgJbM3LOCQ== + dependencies: + clean-stack "^3.0.0" + fs-extra "^8.1" + indent-string "^4.0.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +"@oclif/help@^1.0.1": + version "1.0.1" + resolved "http://localhost:4873/@oclif%2fhelp/-/help-1.0.1.tgz#fd96a3dd9fb2314479e6c8584c91b63754a7dff5" + integrity sha512-8rsl4RHL5+vBUAKBL6PFI3mj58hjPCp2VYyXD4TAa7IMStikFfOH2gtWmqLzIlxAED2EpD0dfYwo9JJxYsH7Aw== + dependencies: + "@oclif/config" "1.18.2" + "@oclif/errors" "1.3.5" + chalk "^4.1.2" + indent-string "^4.0.0" + lodash "^4.17.21" + string-width "^4.2.0" + strip-ansi "^6.0.0" + widest-line "^3.1.0" + wrap-ansi "^6.2.0" + +"@oclif/linewrap@^1.0.0": + version "1.0.0" + resolved "http://localhost:4873/@oclif%2flinewrap/-/linewrap-1.0.0.tgz#aedcb64b479d4db7be24196384897b5000901d91" + integrity sha512-Ups2dShK52xXa8w6iBWLgcjPJWjais6KPJQq3gQ/88AY6BXoTX+MIGFPrWQO1KLMiQfoTpcLnUwloN4brrVUHw== + +"@oclif/parser@^3.8.0", "@oclif/parser@^3.8.6": + version "3.8.6" + resolved "http://localhost:4873/@oclif%2fparser/-/parser-3.8.6.tgz#d5a108af9c708a051cc6b1d27d47359d75f41236" + integrity sha512-tXb0NKgSgNxmf6baN6naK+CCwOueaFk93FG9u202U7mTBHUKsioOUlw1SG/iPi9aJM3WE4pHLXmty59pci0OEw== + dependencies: + "@oclif/errors" "^1.2.2" + "@oclif/linewrap" "^1.0.0" + chalk "^4.1.0" + tslib "^2.0.0" + +"@oclif/plugin-help@^3": + version "3.3.1" + resolved "http://localhost:4873/@oclif%2fplugin-help/-/plugin-help-3.3.1.tgz#36adb4e0173f741df409bb4b69036d24a53bfb24" + integrity sha512-QuSiseNRJygaqAdABYFWn/H1CwIZCp9zp/PLid6yXvy6VcQV7OenEFF5XuYaCvSARe2Tg9r8Jqls5+fw1A9CbQ== + dependencies: + "@oclif/command" "^1.8.15" + "@oclif/config" "1.18.2" + "@oclif/errors" "1.3.5" + "@oclif/help" "^1.0.1" + chalk "^4.1.2" + indent-string "^4.0.0" + lodash "^4.17.21" + string-width "^4.2.0" + strip-ansi "^6.0.0" + widest-line "^3.1.0" + wrap-ansi "^6.2.0" + +"@oclif/screen@^1.0.4": + version "1.0.4" + resolved "http://localhost:4873/@oclif%2fscreen/-/screen-1.0.4.tgz#b740f68609dfae8aa71c3a6cab15d816407ba493" + integrity sha512-60CHpq+eqnTxLZQ4PGHYNwUX572hgpMHGPtTWMjdTMsAvlm69lZV/4ly6O3sAYkomo4NggGcomrDpBe34rxUqw== + +"@sendgrid/client@^7.6.0": + version "7.6.0" + resolved "http://localhost:4873/@sendgrid%2fclient/-/client-7.6.0.tgz#f90cb8759c96e1d90224f29ad98f8fdc2be287f3" + integrity sha512-cpBVZKLlMTO+vpE18krTixubYmZa98oTbLkqBDuTiA3zRkW+urrxg7pDR24TkI35Mid0Zru8jDHwnOiqrXu0TA== + dependencies: + "@sendgrid/helpers" "^7.6.0" + axios "^0.21.4" + +"@sendgrid/helpers@^7.6.0": + version "7.6.0" + resolved "http://localhost:4873/@sendgrid%2fhelpers/-/helpers-7.6.0.tgz#b381bfab391bcd66c771811b22bb6bb2d5c1dfc6" + integrity sha512-0uWD+HSXLl4Z/X3cN+UMQC20RE7xwAACgppnfjDyvKG0KvJcUgDGz7HDdQkiMUdcVWfmyk6zKSg7XKfKzBjTwA== + dependencies: + deepmerge "^4.2.2" + +"@sendgrid/mail@^7.1.1": + version "7.6.0" + resolved "http://localhost:4873/@sendgrid%2fmail/-/mail-7.6.0.tgz#e74ee30110527feab5d3b83d68af0cd94537f6d2" + integrity sha512-0KdaSZzflJD/vUAZjB3ALBIuaVGoLq22hrb2fvQXZHRepU/yhRNlEOqrr05MfKBnKskzq1blnD1J0fHxiwaolw== + dependencies: + "@sendgrid/client" "^7.6.0" + "@sendgrid/helpers" "^7.6.0" + +"@sideway/address@^4.1.3": + version "4.1.3" + resolved "http://localhost:4873/@sideway%2faddress/-/address-4.1.3.tgz#d93cce5d45c5daec92ad76db492cc2ee3c64ab27" + integrity sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ== + dependencies: + "@hapi/hoek" "^9.0.0" + +"@sideway/formula@^3.0.0": + version "3.0.0" + resolved "http://localhost:4873/@sideway%2fformula/-/formula-3.0.0.tgz#fe158aee32e6bd5de85044be615bc08478a0a13c" + integrity sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg== + +"@sideway/pinpoint@^2.0.0": + version "2.0.0" + resolved "http://localhost:4873/@sideway%2fpinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" + integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== + +"@sinonjs/commons@^1.7.0": + version "1.8.3" + resolved "http://localhost:4873/@sinonjs%2fcommons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^6.0.1": + version "6.0.1" + resolved "http://localhost:4873/@sinonjs%2ffake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" + integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== + dependencies: + "@sinonjs/commons" "^1.7.0" + +"@sqltools/formatter@^1.2.2": + version "1.2.3" + resolved "http://localhost:4873/@sqltools%2fformatter/-/formatter-1.2.3.tgz#1185726610acc37317ddab11c3c7f9066966bd20" + integrity sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg== + +"@tootallnate/once@1": + version "1.1.2" + resolved "http://localhost:4873/@tootallnate%2fonce/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": + version "7.1.18" + resolved "http://localhost:4873/@types%2fbabel__core/-/babel__core-7.1.18.tgz#1a29abcc411a9c05e2094c98f9a1b7da6cdf49f8" + integrity sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.4" + resolved "http://localhost:4873/@types%2fbabel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" + integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "http://localhost:4873/@types%2fbabel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": + version "7.14.2" + resolved "http://localhost:4873/@types%2fbabel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" + integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== + dependencies: + "@babel/types" "^7.3.0" + +"@types/graceful-fs@^4.1.2": + version "4.1.5" + resolved "http://localhost:4873/@types%2fgraceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" + integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.4" + resolved "http://localhost:4873/@types%2fistanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "http://localhost:4873/@types%2fistanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "http://localhost:4873/@types%2fistanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/lodash@^4.14.168": + version "4.14.178" + resolved "http://localhost:4873/@types%2flodash/-/lodash-4.14.178.tgz#341f6d2247db528d4a13ddbb374bcdc80406f4f8" + integrity sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw== + +"@types/node@*": + version "17.0.8" + resolved "http://localhost:4873/@types%2fnode/-/node-17.0.8.tgz#50d680c8a8a78fe30abe6906453b21ad8ab0ad7b" + integrity sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg== + +"@types/normalize-package-data@^2.4.0": + version "2.4.1" + resolved "http://localhost:4873/@types%2fnormalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" + integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== + +"@types/prettier@^2.0.0": + version "2.4.2" + resolved "http://localhost:4873/@types%2fprettier/-/prettier-2.4.2.tgz#4c62fae93eb479660c3bd93f9d24d561597a8281" + integrity sha512-ekoj4qOQYp7CvjX8ZDBgN86w3MqQhLE1hczEJbEIjgFEumDy+na/4AJAbLXfgEWFNB2pKadM5rPFtuSGMWK7xA== + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "http://localhost:4873/@types%2fstack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + +"@types/yargs-parser@*": + version "20.2.1" + resolved "http://localhost:4873/@types%2fyargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" + integrity sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw== + +"@types/yargs@^15.0.0": + version "15.0.14" + resolved "http://localhost:4873/@types%2fyargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06" + integrity sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ== + dependencies: + "@types/yargs-parser" "*" + +"@types/zen-observable@0.8.3": + version "0.8.3" + resolved "http://localhost:4873/@types%2fzen-observable/-/zen-observable-0.8.3.tgz#781d360c282436494b32fe7d9f7f8e64b3118aa3" + integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== + +abab@^2.0.3, abab@^2.0.5: + version "2.0.5" + resolved "http://localhost:4873/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" + integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== + +abbrev@1: + version "1.1.1" + resolved "http://localhost:4873/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +accepts@~1.3.7: + version "1.3.7" + resolved "http://localhost:4873/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn-globals@^6.0.0: + version "6.0.0" + resolved "http://localhost:4873/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" + +acorn-walk@^7.1.1: + version "7.2.0" + resolved "http://localhost:4873/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + +acorn@^7.1.1: + version "7.4.1" + resolved "http://localhost:4873/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.2.4: + version "8.7.0" + resolved "http://localhost:4873/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" + integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== + +agent-base@6: + version "6.0.2" + resolved "http://localhost:4873/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + +ajv@^6.12.3: + version "6.12.6" + resolved "http://localhost:4873/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-align@^3.0.0: + version "3.0.1" + resolved "http://localhost:4873/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" + integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== + dependencies: + string-width "^4.1.0" + +ansi-escapes@^3.1.0: + version "3.2.0" + resolved "http://localhost:4873/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + +ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: + version "4.3.2" + resolved "http://localhost:4873/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "http://localhost:4873/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^5.0.0, ansi-regex@^5.0.1: + version "5.0.1" + resolved "http://localhost:4873/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "http://localhost:4873/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0, ansi-styles@^4.2.0: + version "4.3.0" + resolved "http://localhost:4873/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansicolors@~0.3.2: + version "0.3.2" + resolved "http://localhost:4873/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" + integrity sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk= + +any-promise@^1.0.0: + version "1.3.0" + resolved "http://localhost:4873/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + +anymatch@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +anymatch@^3.0.3, anymatch@~3.1.2: + version "3.1.2" + resolved "http://localhost:4873/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +app-root-path@^3.0.0: + version "3.0.0" + resolved "http://localhost:4873/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad" + integrity sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw== + +append-field@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" + integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY= + +aproba@^1.0.3: + version "1.2.0" + resolved "http://localhost:4873/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +are-we-there-yet@~1.1.2: + version "1.1.7" + resolved "http://localhost:4873/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" + integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.10" + resolved "http://localhost:4873/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "http://localhost:4873/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +arr-diff@^4.0.0: + version "4.0.0" + resolved "http://localhost:4873/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-flatten@^1.1.0: + version "1.1.0" + resolved "http://localhost:4873/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-union@^3.1.0: + version "3.1.0" + resolved "http://localhost:4873/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-flatten@1.1.1: + version "1.1.1" + resolved "http://localhost:4873/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + +array-union@^2.1.0: + version "2.1.0" + resolved "http://localhost:4873/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array-unique@^0.3.2: + version "0.3.2" + resolved "http://localhost:4873/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +asn1@~0.2.3: + version "0.2.6" + resolved "http://localhost:4873/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +async@^3.2.3: + version "3.2.3" + resolved "http://localhost:4873/async/-/async-3.2.3.tgz#ac53dafd3f4720ee9e8a160628f18ea91df196c9" + integrity sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g== + +asynckit@^0.4.0: + version "0.4.0" + resolved "http://localhost:4873/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +atob@^2.1.2: + version "2.1.2" + resolved "http://localhost:4873/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +awilix@^4.2.3: + version "4.3.4" + resolved "http://localhost:4873/awilix/-/awilix-4.3.4.tgz#aeecc662efa96256981af3bc6243eb201c8b4a4f" + integrity sha512-NgRwUPxUnoK+OTRa2fXcRQVFPOPQXlwCN1FJPkhO3IHKQJHokhdVpDfgz9L3VZTcA1iSaOFE3N/Q/5P7lIDqig== + dependencies: + camel-case "^4.1.2" + glob "^7.1.6" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "http://localhost:4873/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.11.0" + resolved "http://localhost:4873/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" + integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== + +axios-retry@^3.1.9: + version "3.2.4" + resolved "http://localhost:4873/axios-retry/-/axios-retry-3.2.4.tgz#f447a53c3456f5bfeca18f20c3a3272207d082ae" + integrity sha512-Co3UXiv4npi6lM963mfnuH90/YFLKWWDmoBYfxkHT5xtkSSWNqK9zdG3fw5/CP/dsoKB5aMMJCsgab+tp1OxLQ== + dependencies: + "@babel/runtime" "^7.15.4" + is-retry-allowed "^2.2.0" + +axios@^0.20.0: + version "0.20.0" + resolved "http://localhost:4873/axios/-/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd" + integrity sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA== + dependencies: + follow-redirects "^1.10.0" + +axios@^0.21.1, axios@^0.21.4: + version "0.21.4" + resolved "http://localhost:4873/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== + dependencies: + follow-redirects "^1.14.0" + +babel-jest@^26.6.3: + version "26.6.3" + resolved "http://localhost:4873/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" + integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA== + dependencies: + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/babel__core" "^7.1.7" + babel-plugin-istanbul "^6.0.0" + babel-preset-jest "^26.6.2" + chalk "^4.0.0" + graceful-fs "^4.2.4" + slash "^3.0.0" + +babel-plugin-dynamic-import-node@^2.3.3: + version "2.3.3" + resolved "http://localhost:4873/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-istanbul@^6.0.0: + version "6.1.1" + resolved "http://localhost:4873/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz#8185bd030348d254c6d7dd974355e6a28b21e62d" + integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" + "@types/babel__traverse" "^7.0.6" + +babel-plugin-polyfill-corejs2@^0.3.0: + version "0.3.0" + resolved "http://localhost:4873/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.0.tgz#407082d0d355ba565af24126fb6cb8e9115251fd" + integrity sha512-wMDoBJ6uG4u4PNFh72Ty6t3EgfA91puCuAwKIazbQlci+ENb/UU9A3xG5lutjUIiXCIn1CY5L15r9LimiJyrSA== + dependencies: + "@babel/compat-data" "^7.13.11" + "@babel/helper-define-polyfill-provider" "^0.3.0" + semver "^6.1.1" + +babel-plugin-polyfill-corejs3@^0.5.0: + version "0.5.0" + resolved "http://localhost:4873/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.0.tgz#f81371be3fe499d39e074e272a1ef86533f3d268" + integrity sha512-Hcrgnmkf+4JTj73GbK3bBhlVPiLL47owUAnoJIf69Hakl3q+KfodbDXiZWGMM7iqCZTxCG3Z2VRfPNYES4rXqQ== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.0" + core-js-compat "^3.20.0" + +babel-plugin-polyfill-regenerator@^0.3.0: + version "0.3.0" + resolved "http://localhost:4873/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.0.tgz#9ebbcd7186e1a33e21c5e20cae4e7983949533be" + integrity sha512-dhAPTDLGoMW5/84wkgwiLRwMnio2i1fUe53EuvtKMv0pn2p3S8OCoV1xAzfJPl0KOX7IB89s2ib85vbYiea3jg== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.0" + +babel-plugin-transform-typescript-metadata@^0.3.1: + version "0.3.2" + resolved "http://localhost:4873/babel-plugin-transform-typescript-metadata/-/babel-plugin-transform-typescript-metadata-0.3.2.tgz#7a327842d8c36ffe07ee1b5276434e56c297c9b7" + integrity sha512-mWEvCQTgXQf48yDqgN7CH50waTyYBeP2Lpqx4nNWab9sxEpdXVeKgfj1qYI2/TgUPQtNFZ85i3PemRtnXVYYJg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "http://localhost:4873/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz#747872b1171df032252426586881d62d31798fee" + integrity sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ== + dependencies: + babel-plugin-jest-hoist "^26.6.2" + babel-preset-current-node-syntax "^1.0.0" + +babel-preset-medusa-package@1.1.19-dev-1642337635041: + version "1.1.19-dev-1642337635041" + resolved "http://localhost:4873/babel-preset-medusa-package/-/babel-preset-medusa-package-1.1.19-dev-1642337635041.tgz#24c6f2db887f35c358270d85cc0f6b6c19f459fe" + integrity sha512-HtrHI6oWUEMyTK9MHKzCg7hzZHgi8+uCIQyTQIY5SYFRA6kZiNl54Wzai/BY26F1j5g0sVNfqmFXdBd53GEz7g== + dependencies: + "@babel/plugin-proposal-class-properties" "^7.12.1" + "@babel/plugin-proposal-decorators" "^7.12.1" + "@babel/plugin-proposal-optional-chaining" "^7.14.2" + "@babel/plugin-transform-classes" "^7.12.1" + "@babel/plugin-transform-instanceof" "^7.12.1" + "@babel/plugin-transform-runtime" "^7.12.1" + "@babel/preset-env" "^7.12.7" + "@babel/preset-typescript" "^7.16.0" + babel-plugin-transform-typescript-metadata "^0.3.1" + core-js "^3.7.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "http://localhost:4873/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-js@^1.3.1: + version "1.5.1" + resolved "http://localhost:4873/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +base@^0.11.1: + version "0.11.2" + resolved "http://localhost:4873/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +basic-auth@~2.0.1: + version "2.0.1" + resolved "http://localhost:4873/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" + integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== + dependencies: + safe-buffer "5.1.2" + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "http://localhost:4873/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "http://localhost:4873/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bl@^4.1.0: + version "4.1.0" + resolved "http://localhost:4873/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + +block-stream@*: + version "0.0.9" + resolved "http://localhost:4873/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= + dependencies: + inherits "~2.0.0" + +body-parser@1.19.1, body-parser@^1.19.0: + version "1.19.1" + resolved "http://localhost:4873/body-parser/-/body-parser-1.19.1.tgz#1499abbaa9274af3ecc9f6f10396c995943e31d4" + integrity sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA== + dependencies: + bytes "3.1.1" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.8.1" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.9.6" + raw-body "2.4.2" + type-is "~1.6.18" + +boxen@^5.0.1: + version "5.1.2" + resolved "http://localhost:4873/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50" + integrity sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ== + dependencies: + ansi-align "^3.0.0" + camelcase "^6.2.0" + chalk "^4.1.0" + cli-boxes "^2.2.1" + string-width "^4.2.2" + type-fest "^0.20.2" + widest-line "^3.1.0" + wrap-ansi "^7.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "http://localhost:4873/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1: + version "2.3.2" + resolved "http://localhost:4873/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +braces@^3.0.1, braces@~3.0.2: + version "3.0.2" + resolved "http://localhost:4873/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + +browserslist@^4.17.5, browserslist@^4.19.1: + version "4.19.1" + resolved "http://localhost:4873/browserslist/-/browserslist-4.19.1.tgz#4ac0435b35ab655896c31d53018b6dd5e9e4c9a3" + integrity sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A== + dependencies: + caniuse-lite "^1.0.30001286" + electron-to-chromium "^1.4.17" + escalade "^3.1.1" + node-releases "^2.0.1" + picocolors "^1.0.0" + +bser@2.1.1: + version "2.1.1" + resolved "http://localhost:4873/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "http://localhost:4873/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= + +buffer-from@^1.0.0: + version "1.1.2" + resolved "http://localhost:4873/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-writer@2.0.0: + version "2.0.0" + resolved "http://localhost:4873/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" + integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== + +buffer@^5.5.0: + version "5.7.1" + resolved "http://localhost:4873/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +buffer@^6.0.3: + version "6.0.3" + resolved "http://localhost:4873/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +bull@^3.12.1: + version "3.29.3" + resolved "http://localhost:4873/bull/-/bull-3.29.3.tgz#5b0059b172685b0d6f011d56214e1898ff3a7a0b" + integrity sha512-MOqV1dKLy1YQgP9m3lFolyMxaU+1+o4afzYYf0H4wNM+x/S0I1QPQfkgGlLiH00EyFrvSmeubeCYFP47rTfpjg== + dependencies: + cron-parser "^2.13.0" + debuglog "^1.0.0" + get-port "^5.1.1" + ioredis "^4.27.0" + lodash "^4.17.21" + p-timeout "^3.2.0" + promise.prototype.finally "^3.1.2" + semver "^7.3.2" + util.promisify "^1.0.1" + uuid "^8.3.0" + +busboy@^0.2.11: + version "0.2.14" + resolved "http://localhost:4873/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453" + integrity sha1-bCpiLvz0fFe7vh4qnDetNseSVFM= + dependencies: + dicer "0.2.5" + readable-stream "1.1.x" + +bytes@3.1.1: + version "3.1.1" + resolved "http://localhost:4873/bytes/-/bytes-3.1.1.tgz#3f018291cb4cbad9accb6e6970bca9c8889e879a" + integrity sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg== + +cache-base@^1.0.1: + version "1.0.1" + resolved "http://localhost:4873/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "http://localhost:4873/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "http://localhost:4873/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camel-case@^4.1.2: + version "4.1.2" + resolved "http://localhost:4873/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" + integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== + dependencies: + pascal-case "^3.1.2" + tslib "^2.0.3" + +camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "http://localhost:4873/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.0.0, camelcase@^6.2.0: + version "6.3.0" + resolved "http://localhost:4873/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001286: + version "1.0.30001298" + resolved "http://localhost:4873/caniuse-lite/-/caniuse-lite-1.0.30001298.tgz#0e690039f62e91c3ea581673d716890512e7ec52" + integrity sha512-AcKqikjMLlvghZL/vfTHorlQsLDhGRalYf1+GmWCf5SCMziSGjRYQW/JEksj14NaYHIR6KIhrFAy0HV5C25UzQ== + +capture-exit@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" + integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== + dependencies: + rsvp "^4.8.4" + +cardinal@^2.1.1: + version "2.1.1" + resolved "http://localhost:4873/cardinal/-/cardinal-2.1.1.tgz#7cc1055d822d212954d07b085dea251cc7bc5505" + integrity sha1-fMEFXYItISlU0HsIXeolHMe8VQU= + dependencies: + ansicolors "~0.3.2" + redeyed "~2.1.0" + +caseless@~0.12.0: + version "0.12.0" + resolved "http://localhost:4873/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +chalk@^2.0.0: + version "2.4.2" + resolved "http://localhost:4873/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: + version "4.1.2" + resolved "http://localhost:4873/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "http://localhost:4873/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +chardet@^0.7.0: + version "0.7.0" + resolved "http://localhost:4873/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +chokidar@^3.4.0, chokidar@^3.4.2: + version "3.5.2" + resolved "http://localhost:4873/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chownr@^1.1.4: + version "1.1.4" + resolved "http://localhost:4873/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + +ci-info@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +ci-info@^3.2.0: + version "3.3.0" + resolved "http://localhost:4873/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" + integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== + +cjs-module-lexer@^0.6.0: + version "0.6.0" + resolved "http://localhost:4873/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz#4186fcca0eae175970aee870b9fe2d6cf8d5655f" + integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw== + +class-transformer@^0.5.1: + version "0.5.1" + resolved "http://localhost:4873/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336" + integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw== + +class-utils@^0.3.5: + version "0.3.6" + resolved "http://localhost:4873/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +class-validator@^0.13.1: + version "0.13.2" + resolved "http://localhost:4873/class-validator/-/class-validator-0.13.2.tgz#64b031e9f3f81a1e1dcd04a5d604734608b24143" + integrity sha512-yBUcQy07FPlGzUjoLuUfIOXzgynnQPPruyK1Ge2B74k9ROwnle1E+NxLWnUv5OLU8hA/qL5leAE9XnXq3byaBw== + dependencies: + libphonenumber-js "^1.9.43" + validator "^13.7.0" + +clean-stack@^3.0.0: + version "3.0.1" + resolved "http://localhost:4873/clean-stack/-/clean-stack-3.0.1.tgz#155bf0b2221bf5f4fba89528d24c5953f17fe3a8" + integrity sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg== + dependencies: + escape-string-regexp "4.0.0" + +cli-boxes@^2.2.1: + version "2.2.1" + resolved "http://localhost:4873/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" + integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "http://localhost:4873/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-highlight@^2.1.11: + version "2.1.11" + resolved "http://localhost:4873/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" + integrity sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg== + dependencies: + chalk "^4.0.0" + highlight.js "^10.7.1" + mz "^2.4.0" + parse5 "^5.1.1" + parse5-htmlparser2-tree-adapter "^6.0.0" + yargs "^16.0.0" + +cli-progress@^3.4.0: + version "3.10.0" + resolved "http://localhost:4873/cli-progress/-/cli-progress-3.10.0.tgz#63fd9d6343c598c93542fdfa3563a8b59887d78a" + integrity sha512-kLORQrhYCAtUPLZxqsAt2YJGOvRdt34+O6jl5cQGb7iF3dM55FQZlTR+rQyIK9JUcO9bBMwZsTlND+3dmFU2Cw== + dependencies: + string-width "^4.2.0" + +cli-spinners@^2.5.0: + version "2.6.1" + resolved "http://localhost:4873/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" + integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== + +cli-ux@^5.4.9: + version "5.6.7" + resolved "http://localhost:4873/cli-ux/-/cli-ux-5.6.7.tgz#32ef9e6cb2b457be834280cc799028a11c8235a8" + integrity sha512-dsKAurMNyFDnO6X1TiiRNiVbL90XReLKcvIq4H777NMqXGBxBws23ag8ubCJE97vVZEgWG2eSUhsyLf63Jv8+g== + dependencies: + "@oclif/command" "^1.8.15" + "@oclif/errors" "^1.3.5" + "@oclif/linewrap" "^1.0.0" + "@oclif/screen" "^1.0.4" + ansi-escapes "^4.3.0" + ansi-styles "^4.2.0" + cardinal "^2.1.1" + chalk "^4.1.0" + clean-stack "^3.0.0" + cli-progress "^3.4.0" + extract-stack "^2.0.0" + fs-extra "^8.1" + hyperlinker "^1.0.0" + indent-string "^4.0.0" + is-wsl "^2.2.0" + js-yaml "^3.13.1" + lodash "^4.17.21" + natural-orderby "^2.0.1" + object-treeify "^1.1.4" + password-prompt "^1.1.2" + semver "^7.3.2" + string-width "^4.2.0" + strip-ansi "^6.0.0" + supports-color "^8.1.0" + supports-hyperlinks "^2.1.0" + tslib "^2.0.0" + +cli-width@^3.0.0: + version "3.0.0" + resolved "http://localhost:4873/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== + +cliui@^6.0.0: + version "6.0.0" + resolved "http://localhost:4873/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + +cliui@^7.0.2: + version "7.0.4" + resolved "http://localhost:4873/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "http://localhost:4873/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +clone@^1.0.2: + version "1.0.4" + resolved "http://localhost:4873/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + +cluster-key-slot@^1.1.0: + version "1.1.0" + resolved "http://localhost:4873/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" + integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== + +co@^4.6.0: + version "4.6.0" + resolved "http://localhost:4873/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + +code-point-at@^1.0.0: + version "1.1.0" + resolved "http://localhost:4873/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "http://localhost:4873/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + +collection-visit@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0, color-convert@^1.9.3: + version "1.9.3" + resolved "http://localhost:4873/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "http://localhost:4873/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "http://localhost:4873/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "http://localhost:4873/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.6.0: + version "1.9.0" + resolved "http://localhost:4873/color-string/-/color-string-1.9.0.tgz#63b6ebd1bec11999d1df3a79a7569451ac2be8aa" + integrity sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.1.3: + version "3.2.1" + resolved "http://localhost:4873/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== + dependencies: + color-convert "^1.9.3" + color-string "^1.6.0" + +colors@1.4.0: + version "1.4.0" + resolved "http://localhost:4873/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + +colorspace@1.1.x: + version "1.1.4" + resolved "http://localhost:4873/colorspace/-/colorspace-1.1.4.tgz#8d442d1186152f60453bf8070cd66eb364e59243" + integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== + dependencies: + color "^3.1.3" + text-hex "1.0.x" + +combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: + version "1.0.8" + resolved "http://localhost:4873/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^4.0.1: + version "4.1.1" + resolved "http://localhost:4873/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + +commondir@^1.0.1: + version "1.0.1" + resolved "http://localhost:4873/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +component-emitter@^1.2.1: + version "1.3.0" + resolved "http://localhost:4873/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +concat-map@0.0.1: + version "0.0.1" + resolved "http://localhost:4873/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@^1.5.2: + version "1.6.2" + resolved "http://localhost:4873/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +configstore@5.0.1: + version "5.0.1" + resolved "http://localhost:4873/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" + integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== + dependencies: + dot-prop "^5.2.0" + graceful-fs "^4.1.2" + make-dir "^3.0.0" + unique-string "^2.0.0" + write-file-atomic "^3.0.0" + xdg-basedir "^4.0.0" + +connect-redis@^5.0.0: + version "5.2.0" + resolved "http://localhost:4873/connect-redis/-/connect-redis-5.2.0.tgz#d38e173f2e2cccecb89b8757ce7627ecdb8e3b94" + integrity sha512-wcv1lZWa2K7RbsdSlrvwApBQFLQx+cia+oirLIeim0axR3D/9ZJbHdeTM/j8tJYYKk34dVs2QPAuAqcIklWD+Q== + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "http://localhost:4873/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + +content-disposition@0.5.4: + version "0.5.4" + resolved "http://localhost:4873/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4: + version "1.0.4" + resolved "http://localhost:4873/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + +convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "http://localhost:4873/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +cookie-parser@^1.4.4: + version "1.4.6" + resolved "http://localhost:4873/cookie-parser/-/cookie-parser-1.4.6.tgz#3ac3a7d35a7a03bbc7e365073a26074824214594" + integrity sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA== + dependencies: + cookie "0.4.1" + cookie-signature "1.0.6" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "http://localhost:4873/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + +cookie@0.4.1: + version "0.4.1" + resolved "http://localhost:4873/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" + integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "http://localhost:4873/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +core-js-compat@^3.20.0, core-js-compat@^3.20.2: + version "3.20.2" + resolved "http://localhost:4873/core-js-compat/-/core-js-compat-3.20.2.tgz#d1ff6936c7330959b46b2e08b122a8b14e26140b" + integrity sha512-qZEzVQ+5Qh6cROaTPFLNS4lkvQ6mBzE3R6A6EEpssj7Zr2egMHgsy4XapdifqJDGC9CBiNv7s+ejI96rLNQFdg== + dependencies: + browserslist "^4.19.1" + semver "7.0.0" + +core-js@^2.6.5: + version "2.6.12" + resolved "http://localhost:4873/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" + integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== + +core-js@^3.20.2, core-js@^3.6.5, core-js@^3.7.0: + version "3.20.2" + resolved "http://localhost:4873/core-js/-/core-js-3.20.2.tgz#46468d8601eafc8b266bd2dd6bf9dee622779581" + integrity sha512-nuqhq11DcOAbFBV4zCbKeGbKQsUDRqTX0oqx7AttUBuqe3h20ixsE039QHelbL6P4h+9kytVqyEtyZ6gsiwEYw== + +core-util-is@1.0.2: + version "1.0.2" + resolved "http://localhost:4873/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +core-util-is@~1.0.0: + version "1.0.3" + resolved "http://localhost:4873/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cors@^2.8.5: + version "2.8.5" + resolved "http://localhost:4873/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +cron-parser@^2.13.0: + version "2.18.0" + resolved "http://localhost:4873/cron-parser/-/cron-parser-2.18.0.tgz#de1bb0ad528c815548371993f81a54e5a089edcf" + integrity sha512-s4odpheTyydAbTBQepsqd2rNWGa2iV3cyo8g7zbI2QQYGLVsfbhmwukayS1XHppe02Oy1fg7mg6xoaraVJeEcg== + dependencies: + is-nan "^1.3.0" + moment-timezone "^0.5.31" + +cross-spawn@^6.0.0, cross-spawn@^6.0.5: + version "6.0.5" + resolved "http://localhost:4873/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^7.0.0, cross-spawn@^7.0.3: + version "7.0.3" + resolved "http://localhost:4873/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +crypto-random-string@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" + integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== + +cssom@^0.4.4: + version "0.4.4" + resolved "http://localhost:4873/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== + +cssom@~0.3.6: + version "0.3.8" + resolved "http://localhost:4873/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^2.3.0: + version "2.3.0" + resolved "http://localhost:4873/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== + dependencies: + cssom "~0.3.6" + +dashdash@^1.12.0: + version "1.14.1" + resolved "http://localhost:4873/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +data-urls@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== + dependencies: + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3: + version "2.6.9" + resolved "http://localhost:4873/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: + version "4.3.3" + resolved "http://localhost:4873/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" + +debug@^3.1.0, debug@^3.2.6: + version "3.2.7" + resolved "http://localhost:4873/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debuglog@^1.0.0: + version "1.0.1" + resolved "http://localhost:4873/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" + integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= + +decamelize@^1.2.0: + version "1.2.0" + resolved "http://localhost:4873/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decimal.js@^10.2.1: + version "10.3.1" + resolved "http://localhost:4873/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "http://localhost:4873/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +deep-extend@^0.6.0: + version "0.6.0" + resolved "http://localhost:4873/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deep-is@~0.1.3: + version "0.1.4" + resolved "http://localhost:4873/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@^4.2.2: + version "4.2.2" + resolved "http://localhost:4873/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + +defaults@^1.0.3: + version "1.0.3" + resolved "http://localhost:4873/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + dependencies: + clone "^1.0.2" + +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + +define-properties@^1.1.3: + version "1.1.3" + resolved "http://localhost:4873/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "http://localhost:4873/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "http://localhost:4873/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "http://localhost:4873/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +delegates@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +denque@^1.1.0, denque@^1.5.0: + version "1.5.1" + resolved "http://localhost:4873/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" + integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== + +depd@~1.1.2: + version "1.1.2" + resolved "http://localhost:4873/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +depd@~2.0.0: + version "2.0.0" + resolved "http://localhost:4873/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +destroy@~1.0.4: + version "1.0.4" + resolved "http://localhost:4873/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detect-libc@^1.0.2: + version "1.0.3" + resolved "http://localhost:4873/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + +detect-newline@^3.0.0: + version "3.1.0" + resolved "http://localhost:4873/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +dicer@0.2.5: + version "0.2.5" + resolved "http://localhost:4873/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f" + integrity sha1-WZbAhrszIYyBLAkL3cCc0S+stw8= + dependencies: + readable-stream "1.1.x" + streamsearch "0.1.2" + +diff-sequences@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" + integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "http://localhost:4873/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +dom-walk@^0.1.0: + version "0.1.2" + resolved "http://localhost:4873/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" + integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== + +domexception@^2.0.1: + version "2.0.1" + resolved "http://localhost:4873/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== + dependencies: + webidl-conversions "^5.0.0" + +dot-prop@^5.2.0: + version "5.3.0" + resolved "http://localhost:4873/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" + integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== + dependencies: + is-obj "^2.0.0" + +dotenv@^8.2.0: + version "8.6.0" + resolved "http://localhost:4873/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" + integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "http://localhost:4873/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ecdsa-sig-formatter@1.0.11: + version "1.0.11" + resolved "http://localhost:4873/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + +ee-first@1.1.1: + version "1.1.1" + resolved "http://localhost:4873/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +electron-to-chromium@^1.4.17: + version "1.4.40" + resolved "http://localhost:4873/electron-to-chromium/-/electron-to-chromium-1.4.40.tgz#f5dbced7bfbc7072e5e7ca5487f8f9a42c8bc768" + integrity sha512-j+eVIyQGt2EU5xPWUblhpp5P5z5xyAdRgzogBgfe2F5JGV17gr9pfzWBua6DlPL00LavbOjxubWkWkbVQe9Wlw== + +emittery@^0.7.1: + version "0.7.2" + resolved "http://localhost:4873/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" + integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "http://localhost:4873/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +enabled@2.0.x: + version "2.0.0" + resolved "http://localhost:4873/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" + integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "http://localhost:4873/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "http://localhost:4873/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +error-ex@^1.3.1: + version "1.3.2" + resolved "http://localhost:4873/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.19.1: + version "1.19.1" + resolved "http://localhost:4873/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" + integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-symbols "^1.0.2" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.1" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.1" + is-string "^1.0.7" + is-weakref "^1.0.1" + object-inspect "^1.11.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "http://localhost:4873/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +escalade@^3.1.1: + version "3.1.1" + resolved "http://localhost:4873/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "http://localhost:4873/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@4.0.0: + version "4.0.0" + resolved "http://localhost:4873/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "http://localhost:4873/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escodegen@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: + version "4.0.1" + resolved "http://localhost:4873/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +estraverse@^5.2.0: + version "5.3.0" + resolved "http://localhost:4873/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "http://localhost:4873/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "http://localhost:4873/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +exec-sh@^0.3.2: + version "0.3.6" + resolved "http://localhost:4873/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" + integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== + +execa@^0.10.0: + version "0.10.0" + resolved "http://localhost:4873/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" + integrity sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw== + dependencies: + cross-spawn "^6.0.0" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^4.0.0: + version "4.1.0" + resolved "http://localhost:4873/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + +execa@^5.1.1: + version "5.1.1" + resolved "http://localhost:4873/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "http://localhost:4873/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "http://localhost:4873/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expect@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" + integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA== + dependencies: + "@jest/types" "^26.6.2" + ansi-styles "^4.0.0" + jest-get-type "^26.3.0" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-regex-util "^26.0.0" + +express-session@^1.17.1: + version "1.17.2" + resolved "http://localhost:4873/express-session/-/express-session-1.17.2.tgz#397020374f9bf7997f891b85ea338767b30d0efd" + integrity sha512-mPcYcLA0lvh7D4Oqr5aNJFMtBMKPLl++OKKxkHzZ0U0oDq1rpKBnkR5f5vCHR26VeArlTOEF9td4x5IjICksRQ== + dependencies: + cookie "0.4.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~2.0.0" + on-headers "~1.0.2" + parseurl "~1.3.3" + safe-buffer "5.2.1" + uid-safe "~2.1.5" + +express@^4.17.1: + version "4.17.2" + resolved "http://localhost:4873/express/-/express-4.17.2.tgz#c18369f265297319beed4e5558753cc8c1364cb3" + integrity sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.1" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.4.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.9.6" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.17.2" + serve-static "1.14.2" + setprototypeof "1.2.0" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "http://localhost:4873/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "http://localhost:4873/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@~3.0.2: + version "3.0.2" + resolved "http://localhost:4873/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +external-editor@^3.0.3: + version "3.1.0" + resolved "http://localhost:4873/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +extglob@^2.0.4: + version "2.0.4" + resolved "http://localhost:4873/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extract-stack@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/extract-stack/-/extract-stack-2.0.0.tgz#11367bc865bfcd9bc0db3123e5edb57786f11f9b" + integrity sha512-AEo4zm+TenK7zQorGK1f9mJ8L14hnTDi2ZQPR+Mub1NX8zimka1mXpV5LpH8x9HoUmFSHZCfLHqWvp0Y4FxxzQ== + +extsprintf@1.3.0: + version "1.3.0" + resolved "http://localhost:4873/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.1" + resolved "http://localhost:4873/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== + +faker@^5.5.3: + version "5.5.3" + resolved "http://localhost:4873/faker/-/faker-5.5.3.tgz#c57974ee484431b25205c2c8dc09fda861e51e0e" + integrity sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g== + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "http://localhost:4873/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.9: + version "3.2.10" + resolved "http://localhost:4873/fast-glob/-/fast-glob-3.2.10.tgz#2734f83baa7f43b7fd41e13bc34438f4ffe284ee" + integrity sha512-s9nFhFnvR63wls6/kM88kQqDhMu0AfdjqouE2l5GVQPbqLgyFjjU5ry/r2yKsJxpb9Py1EYNqieFrmMaX4v++A== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "http://localhost:4873/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "http://localhost:4873/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +fastq@^1.6.0: + version "1.13.0" + resolved "http://localhost:4873/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + +fb-watchman@^2.0.0: + version "2.0.1" + resolved "http://localhost:4873/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + dependencies: + bser "2.1.1" + +fecha@^4.2.0: + version "4.2.1" + resolved "http://localhost:4873/fecha/-/fecha-4.2.1.tgz#0a83ad8f86ef62a091e22bb5a039cd03d23eecce" + integrity sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q== + +fengari-interop@^0.1.2: + version "0.1.3" + resolved "http://localhost:4873/fengari-interop/-/fengari-interop-0.1.3.tgz#3ad37a90e7430b69b365441e9fc0ba168942a146" + integrity sha512-EtZ+oTu3kEwVJnoymFPBVLIbQcCoy9uWCVnMA6h3M/RqHkUBsLYp29+RRHf9rKr6GwjubWREU1O7RretFIXjHw== + +fengari@^0.1.4: + version "0.1.4" + resolved "http://localhost:4873/fengari/-/fengari-0.1.4.tgz#72416693cd9e43bd7d809d7829ddc0578b78b0bb" + integrity sha512-6ujqUuiIYmcgkGz8MGAdERU57EIluGGPSUgGPTsco657EHa+srq0S3/YUl/r9kx1+D+d4rGfYObd+m8K22gB1g== + dependencies: + readline-sync "^1.4.9" + sprintf-js "^1.1.1" + tmp "^0.0.33" + +figures@^3.0.0: + version "3.2.0" + resolved "http://localhost:4873/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +fill-range@^4.0.0: + version "4.0.0" + resolved "http://localhost:4873/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "http://localhost:4873/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@~1.1.2: + version "1.1.2" + resolved "http://localhost:4873/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-cache-dir@^2.0.0: + version "2.1.0" + resolved "http://localhost:4873/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== + dependencies: + commondir "^1.0.1" + make-dir "^2.0.0" + pkg-dir "^3.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "http://localhost:4873/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "http://localhost:4873/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +fn.name@1.x.x: + version "1.1.0" + resolved "http://localhost:4873/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" + integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== + +follow-redirects@^1.10.0, follow-redirects@^1.14.0: + version "1.14.7" + resolved "http://localhost:4873/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685" + integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ== + +for-each@^0.3.3: + version "0.3.3" + resolved "http://localhost:4873/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +for-in@^1.0.2: + version "1.0.2" + resolved "http://localhost:4873/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +forever-agent@~0.6.1: + version "0.6.1" + resolved "http://localhost:4873/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +form-data@^3.0.0: + version "3.0.1" + resolved "http://localhost:4873/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +form-data@~2.3.2: + version "2.3.3" + resolved "http://localhost:4873/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +forwarded@0.2.0: + version "0.2.0" + resolved "http://localhost:4873/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "http://localhost:4873/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2: + version "0.5.2" + resolved "http://localhost:4873/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +fs-exists-cached@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/fs-exists-cached/-/fs-exists-cached-1.0.0.tgz#cf25554ca050dc49ae6656b41de42258989dcbce" + integrity sha1-zyVVTKBQ3EmuZla0HeQiWJidy84= + +fs-extra@^10.0.0: + version "10.0.0" + resolved "http://localhost:4873/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" + integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-extra@^8.1: + version "8.1.0" + resolved "http://localhost:4873/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-minipass@^1.2.7: + version "1.2.7" + resolved "http://localhost:4873/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" + integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== + dependencies: + minipass "^2.6.0" + +fs-readdir-recursive@^1.1.0: + version "1.1.0" + resolved "http://localhost:4873/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" + integrity sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^2.1.2, fsevents@~2.3.2: + version "2.3.2" + resolved "http://localhost:4873/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +fstream@^1.0.0, fstream@^1.0.12: + version "1.0.12" + resolved "http://localhost:4873/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" + integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +function-bind@^1.1.1: + version "1.1.1" + resolved "http://localhost:4873/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gauge@~2.7.3: + version "2.7.4" + resolved "http://localhost:4873/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "http://localhost:4873/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.1, get-caller-file@^2.0.5: + version "2.0.5" + resolved "http://localhost:4873/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: + version "1.1.1" + resolved "http://localhost:4873/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + +get-package-type@^0.1.0: + version "0.1.0" + resolved "http://localhost:4873/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-port@^5.1.1: + version "5.1.1" + resolved "http://localhost:4873/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" + integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== + +get-stream@^3.0.0: + version "3.0.0" + resolved "http://localhost:4873/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + +get-stream@^4.0.0: + version "4.1.0" + resolved "http://localhost:4873/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-stream@^5.0.0: + version "5.2.0" + resolved "http://localhost:4873/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +get-stream@^6.0.0: + version "6.0.1" + resolved "http://localhost:4873/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "http://localhost:4873/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +getpass@^0.1.1: + version "0.1.7" + resolved "http://localhost:4873/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "http://localhost:4873/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: + version "7.2.0" + resolved "http://localhost:4873/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global@^4.4.0: + version "4.4.0" + resolved "http://localhost:4873/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" + integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== + dependencies: + min-document "^2.19.0" + process "^0.11.10" + +globals@^11.1.0: + version "11.12.0" + resolved "http://localhost:4873/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globby@^11.0.1: + version "11.1.0" + resolved "http://localhost:4873/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: + version "4.2.9" + resolved "http://localhost:4873/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" + integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== + +growly@^1.3.0: + version "1.3.0" + resolved "http://localhost:4873/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= + +har-schema@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.3: + version "5.1.5" + resolved "http://localhost:4873/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + +has-bigints@^1.0.1: + version "1.0.1" + resolved "http://localhost:4873/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== + +has-flag@^3.0.0: + version "3.0.0" + resolved "http://localhost:4873/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "http://localhost:4873/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.1, has-symbols@^1.0.2: + version "1.0.2" + resolved "http://localhost:4873/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423" + integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "http://localhost:4873/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + +has-value@^0.3.1: + version "0.3.1" + resolved "http://localhost:4873/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "http://localhost:4873/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.3: + version "1.0.3" + resolved "http://localhost:4873/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +highlight.js@^10.7.1: + version "10.7.3" + resolved "http://localhost:4873/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" + integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== + +homedir-polyfill@^1.0.1: + version "1.0.3" + resolved "http://localhost:4873/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" + integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== + dependencies: + parse-passwd "^1.0.0" + +hosted-git-info@^2.1.4: + version "2.8.9" + resolved "http://localhost:4873/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== + +hosted-git-info@^4.0.2: + version "4.1.0" + resolved "http://localhost:4873/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" + integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== + dependencies: + lru-cache "^6.0.0" + +html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "http://localhost:4873/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== + dependencies: + whatwg-encoding "^1.0.5" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "http://localhost:4873/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +http-errors@1.8.1: + version "1.8.1" + resolved "http://localhost:4873/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" + integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.1" + +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "http://localhost:4873/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + +http-signature@~1.2.0: + version "1.2.0" + resolved "http://localhost:4873/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-proxy-agent@^5.0.0: + version "5.0.0" + resolved "http://localhost:4873/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== + dependencies: + agent-base "6" + debug "4" + +human-signals@^1.1.1: + version "1.1.1" + resolved "http://localhost:4873/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== + +human-signals@^2.1.0: + version "2.1.0" + resolved "http://localhost:4873/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +hyperlinker@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/hyperlinker/-/hyperlinker-1.0.0.tgz#23dc9e38a206b208ee49bc2d6c8ef47027df0c0e" + integrity sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ== + +iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: + version "0.4.24" + resolved "http://localhost:4873/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.1.13, ieee754@^1.2.1: + version "1.2.1" + resolved "http://localhost:4873/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore-walk@^3.0.1: + version "3.0.4" + resolved "http://localhost:4873/ignore-walk/-/ignore-walk-3.0.4.tgz#c9a09f69b7c7b479a5d74ac1a3c0d4236d2a6335" + integrity sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ== + dependencies: + minimatch "^3.0.4" + +ignore@^5.2.0: + version "5.2.0" + resolved "http://localhost:4873/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + +import-local@^3.0.2: + version "3.1.0" + resolved "http://localhost:4873/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "http://localhost:4873/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +indent-string@^4.0.0: + version "4.0.0" + resolved "http://localhost:4873/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflight@^1.0.4: + version "1.0.6" + resolved "http://localhost:4873/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "http://localhost:4873/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@~1.3.0: + version "1.3.8" + resolved "http://localhost:4873/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +inquirer@^8.0.0: + version "8.2.0" + resolved "http://localhost:4873/inquirer/-/inquirer-8.2.0.tgz#f44f008dd344bbfc4b30031f45d984e034a3ac3a" + integrity sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.1" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.21" + mute-stream "0.0.8" + ora "^5.4.1" + run-async "^2.4.0" + rxjs "^7.2.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + +internal-slot@^1.0.3: + version "1.0.3" + resolved "http://localhost:4873/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + +ioredis-mock@^5.6.0: + version "5.8.1" + resolved "http://localhost:4873/ioredis-mock/-/ioredis-mock-5.8.1.tgz#5221260a7165c1d0a6db40f7245d7eb8996cd9d2" + integrity sha512-YWUoE7ZZLzo2fJMWLjeh3F/TkgHqeazdOeExZskit+/2ZSA0bsFPkXiKMOUHZxjOk2JskOP9iuYvf/iO3mhMZg== + dependencies: + fengari "^0.1.4" + fengari-interop "^0.1.2" + lodash "^4.17.21" + standard-as-callback "^2.1.0" + +ioredis@^4.17.3, ioredis@^4.27.0: + version "4.28.2" + resolved "http://localhost:4873/ioredis/-/ioredis-4.28.2.tgz#493ccd5d869fd0ec86c96498192718171f6c9203" + integrity sha512-kQ+Iv7+c6HsDdPP2XUHaMv8DhnSeAeKEwMbaoqsXYbO+03dItXt7+5jGQDRyjdRUV2rFJbzg7P4Qt1iX2tqkOg== + dependencies: + cluster-key-slot "^1.1.0" + debug "^4.3.1" + denque "^1.1.0" + lodash.defaults "^4.2.0" + lodash.flatten "^4.4.0" + lodash.isarguments "^3.1.0" + p-map "^2.1.0" + redis-commands "1.7.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "http://localhost:4873/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "http://localhost:4873/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "http://localhost:4873/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "http://localhost:4873/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-bigint@^1.0.1: + version "1.0.4" + resolved "http://localhost:4873/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "http://localhost:4873/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "http://localhost:4873/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-buffer@^1.1.5: + version "1.1.6" + resolved "http://localhost:4873/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.4: + version "1.2.4" + resolved "http://localhost:4873/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== + +is-ci@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + +is-core-module@^2.8.0: + version "2.8.1" + resolved "http://localhost:4873/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" + integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== + dependencies: + has "^1.0.3" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "http://localhost:4873/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "http://localhost:4873/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "http://localhost:4873/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "http://localhost:4873/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-docker@^2.0.0, is-docker@^2.1.1, is-docker@^2.2.1: + version "2.2.1" + resolved "http://localhost:4873/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "http://localhost:4873/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "http://localhost:4873/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= + +is-extglob@^2.1.1: + version "2.1.1" + resolved "http://localhost:4873/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "http://localhost:4873/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "http://localhost:4873/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^2.0.0: + version "2.0.1" + resolved "http://localhost:4873/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= + dependencies: + is-extglob "^1.0.0" + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "http://localhost:4873/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-interactive@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" + integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== + +is-invalid-path@^0.1.0: + version "0.1.0" + resolved "http://localhost:4873/is-invalid-path/-/is-invalid-path-0.1.0.tgz#307a855b3cf1a938b44ea70d2c61106053714f34" + integrity sha1-MHqFWzzxqTi0TqcNLGEQYFNxTzQ= + dependencies: + is-glob "^2.0.0" + +is-nan@^1.3.0: + version "1.3.2" + resolved "http://localhost:4873/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" + integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + +is-negative-zero@^2.0.1: + version "2.0.2" + resolved "http://localhost:4873/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.6" + resolved "http://localhost:4873/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" + integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== + dependencies: + has-tostringtag "^1.0.0" + +is-number@^3.0.0: + version "3.0.0" + resolved "http://localhost:4873/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-number@^4.0.0: + version "4.0.0" + resolved "http://localhost:4873/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== + +is-number@^7.0.0: + version "7.0.0" + resolved "http://localhost:4873/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-obj@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + +is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "http://localhost:4873/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "http://localhost:4873/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + +is-regex@^1.1.4: + version "1.1.4" + resolved "http://localhost:4873/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-retry-allowed@^2.2.0: + version "2.2.0" + resolved "http://localhost:4873/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz#88f34cbd236e043e71b6932d09b0c65fb7b4d71d" + integrity sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg== + +is-shared-array-buffer@^1.0.1: + version "1.0.1" + resolved "http://localhost:4873/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" + integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== + +is-stream@^1.1.0: + version "1.1.0" + resolved "http://localhost:4873/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-stream@^2.0.0: + version "2.0.1" + resolved "http://localhost:4873/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "http://localhost:4873/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "http://localhost:4873/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typedarray@^1.0.0, is-typedarray@~1.0.0: + version "1.0.0" + resolved "http://localhost:4873/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "http://localhost:4873/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +is-valid-path@^0.1.1: + version "0.1.1" + resolved "http://localhost:4873/is-valid-path/-/is-valid-path-0.1.1.tgz#110f9ff74c37f663e1ec7915eb451f2db93ac9df" + integrity sha1-EQ+f90w39mPh7HkV60UfLbk6yd8= + dependencies: + is-invalid-path "^0.1.0" + +is-weakref@^1.0.1: + version "1.0.2" + resolved "http://localhost:4873/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +is-windows@^1.0.2: + version "1.0.2" + resolved "http://localhost:4873/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-wsl@^2.1.1, is-wsl@^2.2.0: + version "2.2.0" + resolved "http://localhost:4873/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +is_js@^0.9.0: + version "0.9.0" + resolved "http://localhost:4873/is_js/-/is_js-0.9.0.tgz#0ab94540502ba7afa24c856aa985561669e9c52d" + integrity sha1-CrlFQFArp6+iTIVqqYVWFmnpxS0= + +isarray@0.0.1: + version "0.0.1" + resolved "http://localhost:4873/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "http://localhost:4873/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isexe@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +iso8601-duration@^1.3.0: + version "1.3.0" + resolved "http://localhost:4873/iso8601-duration/-/iso8601-duration-1.3.0.tgz#29d7b69e0574e4acdee50c5e5e09adab4137ba5a" + integrity sha512-K4CiUBzo3YeWk76FuET/dQPH03WE04R94feo5TSKQCXpoXQt9E4yx2CnY737QZnSAI3PI4WlKo/zfqizGx52QQ== + +isobject@^2.0.0: + version "2.1.0" + resolved "http://localhost:4873/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "http://localhost:4873/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +isstream@~0.1.2: + version "0.1.2" + resolved "http://localhost:4873/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "http://localhost:4873/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-instrument@^4.0.3: + version "4.0.3" + resolved "http://localhost:4873/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" + integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== + dependencies: + "@babel/core" "^7.7.5" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.0.0" + semver "^6.3.0" + +istanbul-lib-instrument@^5.0.4: + version "5.1.0" + resolved "http://localhost:4873/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz#7b49198b657b27a730b8e9cb601f1e1bff24c59a" + integrity sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "http://localhost:4873/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "http://localhost:4873/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.0.2: + version "3.1.3" + resolved "http://localhost:4873/istanbul-reports/-/istanbul-reports-3.1.3.tgz#4bcae3103b94518117930d51283690960b50d3c2" + integrity sha512-x9LtDVtfm/t1GFiLl3NffC7hz+I1ragvgX1P/Lg1NlIagifZDKUkuuaAxH/qpwj2IuEfD8G2Bs/UKp+sZ/pKkg== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0" + integrity sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ== + dependencies: + "@jest/types" "^26.6.2" + execa "^4.0.0" + throat "^5.0.0" + +jest-cli@^26.6.3: + version "26.6.3" + resolved "http://localhost:4873/jest-cli/-/jest-cli-26.6.3.tgz#43117cfef24bc4cd691a174a8796a532e135e92a" + integrity sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg== + dependencies: + "@jest/core" "^26.6.3" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.4" + import-local "^3.0.2" + is-ci "^2.0.0" + jest-config "^26.6.3" + jest-util "^26.6.2" + jest-validate "^26.6.2" + prompts "^2.0.1" + yargs "^15.4.1" + +jest-config@^26.6.3: + version "26.6.3" + resolved "http://localhost:4873/jest-config/-/jest-config-26.6.3.tgz#64f41444eef9eb03dc51d5c53b75c8c71f645349" + integrity sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg== + dependencies: + "@babel/core" "^7.1.0" + "@jest/test-sequencer" "^26.6.3" + "@jest/types" "^26.6.2" + babel-jest "^26.6.3" + chalk "^4.0.0" + deepmerge "^4.2.2" + glob "^7.1.1" + graceful-fs "^4.2.4" + jest-environment-jsdom "^26.6.2" + jest-environment-node "^26.6.2" + jest-get-type "^26.3.0" + jest-jasmine2 "^26.6.3" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" + micromatch "^4.0.2" + pretty-format "^26.6.2" + +jest-diff@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" + integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== + dependencies: + chalk "^4.0.0" + diff-sequences "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" + +jest-docblock@^26.0.0: + version "26.0.0" + resolved "http://localhost:4873/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" + integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== + dependencies: + detect-newline "^3.0.0" + +jest-each@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/jest-each/-/jest-each-26.6.2.tgz#02526438a77a67401c8a6382dfe5999952c167cb" + integrity sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A== + dependencies: + "@jest/types" "^26.6.2" + chalk "^4.0.0" + jest-get-type "^26.3.0" + jest-util "^26.6.2" + pretty-format "^26.6.2" + +jest-environment-jsdom@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz#78d09fe9cf019a357009b9b7e1f101d23bd1da3e" + integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q== + dependencies: + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + jest-util "^26.6.2" + jsdom "^16.4.0" + +jest-environment-node@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/jest-environment-node/-/jest-environment-node-26.6.2.tgz#824e4c7fb4944646356f11ac75b229b0035f2b0c" + integrity sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag== + dependencies: + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + jest-util "^26.6.2" + +jest-get-type@^26.3.0: + version "26.3.0" + resolved "http://localhost:4873/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" + integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== + +jest-haste-map@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" + integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w== + dependencies: + "@jest/types" "^26.6.2" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.4" + jest-regex-util "^26.0.0" + jest-serializer "^26.6.2" + jest-util "^26.6.2" + jest-worker "^26.6.2" + micromatch "^4.0.2" + sane "^4.0.3" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.1.2" + +jest-jasmine2@^26.6.3: + version "26.6.3" + resolved "http://localhost:4873/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz#adc3cf915deacb5212c93b9f3547cd12958f2edd" + integrity sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg== + dependencies: + "@babel/traverse" "^7.1.0" + "@jest/environment" "^26.6.2" + "@jest/source-map" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + expect "^26.6.2" + is-generator-fn "^2.0.0" + jest-each "^26.6.2" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-runtime "^26.6.3" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + pretty-format "^26.6.2" + throat "^5.0.0" + +jest-leak-detector@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz#7717cf118b92238f2eba65054c8a0c9c653a91af" + integrity sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg== + dependencies: + jest-get-type "^26.3.0" + pretty-format "^26.6.2" + +jest-matcher-utils@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz#8e6fd6e863c8b2d31ac6472eeb237bc595e53e7a" + integrity sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw== + dependencies: + chalk "^4.0.0" + jest-diff "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" + +jest-message-util@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" + integrity sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA== + dependencies: + "@babel/code-frame" "^7.0.0" + "@jest/types" "^26.6.2" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" + micromatch "^4.0.2" + pretty-format "^26.6.2" + slash "^3.0.0" + stack-utils "^2.0.2" + +jest-mock@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" + integrity sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew== + dependencies: + "@jest/types" "^26.6.2" + "@types/node" "*" + +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "http://localhost:4873/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== + +jest-regex-util@^26.0.0: + version "26.0.0" + resolved "http://localhost:4873/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" + integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== + +jest-resolve-dependencies@^26.6.3: + version "26.6.3" + resolved "http://localhost:4873/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz#6680859ee5d22ee5dcd961fe4871f59f4c784fb6" + integrity sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg== + dependencies: + "@jest/types" "^26.6.2" + jest-regex-util "^26.0.0" + jest-snapshot "^26.6.2" + +jest-resolve@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/jest-resolve/-/jest-resolve-26.6.2.tgz#a3ab1517217f469b504f1b56603c5bb541fbb507" + integrity sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ== + dependencies: + "@jest/types" "^26.6.2" + chalk "^4.0.0" + graceful-fs "^4.2.4" + jest-pnp-resolver "^1.2.2" + jest-util "^26.6.2" + read-pkg-up "^7.0.1" + resolve "^1.18.1" + slash "^3.0.0" + +jest-runner@^26.6.3: + version "26.6.3" + resolved "http://localhost:4873/jest-runner/-/jest-runner-26.6.3.tgz#2d1fed3d46e10f233fd1dbd3bfaa3fe8924be159" + integrity sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ== + dependencies: + "@jest/console" "^26.6.2" + "@jest/environment" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.7.1" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-config "^26.6.3" + jest-docblock "^26.0.0" + jest-haste-map "^26.6.2" + jest-leak-detector "^26.6.2" + jest-message-util "^26.6.2" + jest-resolve "^26.6.2" + jest-runtime "^26.6.3" + jest-util "^26.6.2" + jest-worker "^26.6.2" + source-map-support "^0.5.6" + throat "^5.0.0" + +jest-runtime@^26.6.3: + version "26.6.3" + resolved "http://localhost:4873/jest-runtime/-/jest-runtime-26.6.3.tgz#4f64efbcfac398331b74b4b3c82d27d401b8fa2b" + integrity sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw== + dependencies: + "@jest/console" "^26.6.2" + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/globals" "^26.6.2" + "@jest/source-map" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/yargs" "^15.0.0" + chalk "^4.0.0" + cjs-module-lexer "^0.6.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.4" + jest-config "^26.6.3" + jest-haste-map "^26.6.2" + jest-message-util "^26.6.2" + jest-mock "^26.6.2" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" + slash "^3.0.0" + strip-bom "^4.0.0" + yargs "^15.4.1" + +jest-serializer@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" + integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.4" + +jest-snapshot@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" + integrity sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og== + dependencies: + "@babel/types" "^7.0.0" + "@jest/types" "^26.6.2" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.0.0" + chalk "^4.0.0" + expect "^26.6.2" + graceful-fs "^4.2.4" + jest-diff "^26.6.2" + jest-get-type "^26.3.0" + jest-haste-map "^26.6.2" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-resolve "^26.6.2" + natural-compare "^1.4.0" + pretty-format "^26.6.2" + semver "^7.3.2" + +jest-util@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" + integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== + dependencies: + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + graceful-fs "^4.2.4" + is-ci "^2.0.0" + micromatch "^4.0.2" + +jest-validate@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" + integrity sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ== + dependencies: + "@jest/types" "^26.6.2" + camelcase "^6.0.0" + chalk "^4.0.0" + jest-get-type "^26.3.0" + leven "^3.1.0" + pretty-format "^26.6.2" + +jest-watcher@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/jest-watcher/-/jest-watcher-26.6.2.tgz#a5b683b8f9d68dbcb1d7dae32172d2cca0592975" + integrity sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ== + dependencies: + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + jest-util "^26.6.2" + string-length "^4.0.1" + +jest-worker@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" + integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^7.0.0" + +jest@^26.6.3: + version "26.6.3" + resolved "http://localhost:4873/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef" + integrity sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q== + dependencies: + "@jest/core" "^26.6.3" + import-local "^3.0.2" + jest-cli "^26.6.3" + +joi-objectid@^3.0.1: + version "3.0.1" + resolved "http://localhost:4873/joi-objectid/-/joi-objectid-3.0.1.tgz#63ace7860f8e1a993a28d40c40ffd8eff01a3668" + integrity sha512-V/3hbTlGpvJ03Me6DJbdBI08hBTasFOmipsauOsxOSnsF1blxV537WTl1zPwbfcKle4AK0Ma4OPnzMH4LlvTpQ== + +joi@^17.3.0: + version "17.5.0" + resolved "http://localhost:4873/joi/-/joi-17.5.0.tgz#7e66d0004b5045d971cf416a55fb61d33ac6e011" + integrity sha512-R7hR50COp7StzLnDi4ywOXHrBrgNXuUUfJWIR5lPY5Bm/pOD3jZaTwpluUXVLRWcoWZxkrHBBJ5hLxgnlehbdw== + dependencies: + "@hapi/hoek" "^9.0.0" + "@hapi/topo" "^5.0.0" + "@sideway/address" "^4.1.3" + "@sideway/formula" "^3.0.0" + "@sideway/pinpoint" "^2.0.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "http://localhost:4873/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "http://localhost:4873/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.0.0: + version "4.1.0" + resolved "http://localhost:4873/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsbn@~0.1.0: + version "0.1.1" + resolved "http://localhost:4873/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +jsdom@^16.4.0: + version "16.7.0" + resolved "http://localhost:4873/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== + dependencies: + abab "^2.0.5" + acorn "^8.2.4" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + form-data "^3.0.0" + html-encoding-sniffer "^2.0.1" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.5.0" + ws "^7.4.6" + xml-name-validator "^3.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "http://localhost:4873/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "http://localhost:4873/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "http://localhost:4873/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "http://localhost:4873/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.4.0: + version "0.4.0" + resolved "http://localhost:4873/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "http://localhost:4873/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +json5@^2.1.2: + version "2.2.0" + resolved "http://localhost:4873/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== + dependencies: + minimist "^1.2.5" + +jsonfile@^4.0.0: + version "4.0.0" + resolved "http://localhost:4873/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^6.0.1: + version "6.1.0" + resolved "http://localhost:4873/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonwebtoken@^8.2.0, jsonwebtoken@^8.5.1: + version "8.5.1" + resolved "http://localhost:4873/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" + integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^5.6.0" + +jsprim@^1.2.2: + version "1.4.2" + resolved "http://localhost:4873/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" + integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.4.0" + verror "1.10.0" + +jwa@^1.4.1: + version "1.4.1" + resolved "http://localhost:4873/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" + integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + +jws@^3.2.2: + version "3.2.2" + resolved "http://localhost:4873/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" + integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== + dependencies: + jwa "^1.4.1" + safe-buffer "^5.0.1" + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "http://localhost:4873/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "http://localhost:4873/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0: + version "5.1.0" + resolved "http://localhost:4873/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.3" + resolved "http://localhost:4873/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +kleur@^3.0.3: + version "3.0.3" + resolved "http://localhost:4873/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +kuler@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" + integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== + +leven@^3.1.0: + version "3.1.0" + resolved "http://localhost:4873/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@~0.3.0: + version "0.3.0" + resolved "http://localhost:4873/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +libphonenumber-js@^1.9.43: + version "1.9.44" + resolved "http://localhost:4873/libphonenumber-js/-/libphonenumber-js-1.9.44.tgz#d036364fe4c1e27205d1d283c7bf8fc25625200b" + integrity sha512-zhw8nUMJuQf7jG1dZfEOKKOS6M3QYIv3HnvB/vGohNd0QfxIQcObH3a6Y6s350H+9xgBeOXClOJkS0hJ0yvS3g== + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "http://localhost:4873/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +locate-path@^3.0.0: + version "3.0.0" + resolved "http://localhost:4873/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "http://localhost:4873/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "http://localhost:4873/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "http://localhost:4873/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" + integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw= + +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "http://localhost:4873/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" + integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= + +lodash.includes@^4.3.0: + version "4.3.0" + resolved "http://localhost:4873/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= + +lodash.isarguments@^3.1.0: + version "3.1.0" + resolved "http://localhost:4873/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= + +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "http://localhost:4873/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= + +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "http://localhost:4873/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "http://localhost:4873/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w= + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "http://localhost:4873/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "http://localhost:4873/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= + +lodash.once@^4.0.0: + version "4.1.1" + resolved "http://localhost:4873/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= + +lodash@^4.17.21, lodash@^4.7.0: + version "4.17.21" + resolved "http://localhost:4873/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@^4.1.0: + version "4.1.0" + resolved "http://localhost:4873/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +logform@^2.3.2: + version "2.3.2" + resolved "http://localhost:4873/logform/-/logform-2.3.2.tgz#68babe6a74ab09a1fd15a9b1e6cbc7713d41cb5b" + integrity sha512-V6JiPThZzTsbVRspNO6TmHkR99oqYTs8fivMBYQkjZj6rxW92KxtDCPE6IkAk1DNBnYKNkjm4jYBm6JDUcyhOA== + dependencies: + colors "1.4.0" + fecha "^4.2.0" + ms "^2.1.1" + safe-stable-stringify "^1.1.0" + triple-beam "^1.3.0" + +lower-case@^2.0.2: + version "2.0.2" + resolved "http://localhost:4873/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "http://localhost:4873/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-dir@^2.0.0, make-dir@^2.1.0: + version "2.1.0" + resolved "http://localhost:4873/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +make-dir@^3.0.0: + version "3.1.0" + resolved "http://localhost:4873/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +makeerror@1.0.12: + version "1.0.12" + resolved "http://localhost:4873/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +map-cache@^0.2.2: + version "0.2.2" + resolved "http://localhost:4873/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-visit@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +math-random@^1.0.1: + version "1.0.4" + resolved "http://localhost:4873/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" + integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== + +meant@^1.0.1: + version "1.0.3" + resolved "http://localhost:4873/meant/-/meant-1.0.3.tgz#67769af9de1d158773e928ae82c456114903554c" + integrity sha512-88ZRGcNxAq4EH38cQ4D85PM57pikCwS8Z99EWHODxN7KBY+UuPiqzRTtZzS8KTXO/ywSWbdjjJST2Hly/EQxLw== + +media-typer@0.3.0: + version "0.3.0" + resolved "http://localhost:4873/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + +medusa-core-utils@1.1.31-dev-1642337635041: + version "1.1.31-dev-1642337635041" + resolved "http://localhost:4873/medusa-core-utils/-/medusa-core-utils-1.1.31-dev-1642337635041.tgz#d6928f377320ab851eff1750e13e44e2e366c9cb" + integrity sha512-m0VXTM3QwKi0oRk2Q4mqn6sK07xJgiwyz3rs/0gHTjl88B8k75XugbriFceLPEYqHs6AjP6nSNiRDqdRJqUsMg== + dependencies: + joi "^17.3.0" + joi-objectid "^3.0.1" + +medusa-fulfillment-webshipper@1.1.35-dev-1642337635041: + version "1.1.35-dev-1642337635041" + resolved "http://localhost:4873/medusa-fulfillment-webshipper/-/medusa-fulfillment-webshipper-1.1.35-dev-1642337635041.tgz#ab4b0a23488094b39582d1c1d1c69e29713b464d" + integrity sha512-P1gRvnJcs5Svgmvb44Qp1Oph9TqtUQsEeawhX7u+3dSz9qDnJ1lo1XB1tBttpCP9qepPe3nc0Sk7mEwlq8eM6Q== + dependencies: + axios "^0.20.0" + body-parser "^1.19.0" + cors "^2.8.5" + express "^4.17.1" + medusa-core-utils "1.1.31-dev-1642337635041" + +medusa-interfaces@1.1.32-dev-1642337635041: + version "1.1.32-dev-1642337635041" + resolved "http://localhost:4873/medusa-interfaces/-/medusa-interfaces-1.1.32-dev-1642337635041.tgz#8179a344a41e1163502b4ee8af5b294443067f99" + integrity sha512-I7Wp+BEgzJ2wLkGBoDe6VhAlB8lJRMAHJ7wGzWfCMiG3Dj0PX2KE2HZDT+PA5S7IIXHWh9c0n37/cHZDcIF5Hw== + dependencies: + medusa-core-utils "1.1.31-dev-1642337635041" + +medusa-plugin-sendgrid@1.1.36-dev-1642337635041: + version "1.1.36-dev-1642337635041" + resolved "http://localhost:4873/medusa-plugin-sendgrid/-/medusa-plugin-sendgrid-1.1.36-dev-1642337635041.tgz#ae4d1d23167daf3c45ced085f3079ed21d5e876d" + integrity sha512-nJBq0x9h9fMsPfW4BnGzvk8yWpuk1v90zeXP85cDhFeAAWJ50o2zF7HsNcJawPfhKooAF+3kRDApR8706gUyqQ== + dependencies: + "@babel/plugin-transform-classes" "^7.9.5" + "@sendgrid/mail" "^7.1.1" + body-parser "^1.19.0" + express "^4.17.1" + medusa-core-utils "1.1.31-dev-1642337635041" + medusa-test-utils "1.1.35-dev-1642337635041" + +medusa-telemetry@0.0.11-dev-1642337635041: + version "0.0.11-dev-1642337635041" + resolved "http://localhost:4873/medusa-telemetry/-/medusa-telemetry-0.0.11-dev-1642337635041.tgz#290bb20c1712adf99ec5d2f6871b200106203bc0" + integrity sha512-LlJVgdKAQFrp6ULW8D+Qvb/VSEgbQbKjEeoMnUwDaMMswGehsFUXsqBzs1LRo5nKmpLaPvSorw4OMvktR+RxTQ== + dependencies: + axios "^0.21.1" + axios-retry "^3.1.9" + boxen "^5.0.1" + ci-info "^3.2.0" + configstore "5.0.1" + global "^4.4.0" + is-docker "^2.2.1" + remove-trailing-slash "^0.1.1" + uuid "^8.3.2" + +medusa-test-utils@1.1.35-dev-1642337635041: + version "1.1.35-dev-1642337635041" + resolved "http://localhost:4873/medusa-test-utils/-/medusa-test-utils-1.1.35-dev-1642337635041.tgz#1daf7f6a671e2fffe43ab349d795581870104a4a" + integrity sha512-pCpMjmo0VyYbSRu/Ga/GdirBscJtS4HK4HtfXepMrut7Yg/kV+GpW/fFtBFkiqGDBpCWYLopzZAdRw+qpdpusA== + dependencies: + "@babel/plugin-transform-classes" "^7.9.5" + medusa-core-utils "1.1.31-dev-1642337635041" + randomatic "^3.1.1" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "http://localhost:4873/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + +merge-stream@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "http://localhost:4873/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +methods@~1.1.2: + version "1.1.2" + resolved "http://localhost:4873/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + +micromatch@^3.1.4: + version "3.1.10" + resolved "http://localhost:4873/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +micromatch@^4.0.2, micromatch@^4.0.4: + version "4.0.4" + resolved "http://localhost:4873/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== + dependencies: + braces "^3.0.1" + picomatch "^2.2.3" + +mime-db@1.51.0: + version "1.51.0" + resolved "http://localhost:4873/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" + integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== + +mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24: + version "2.1.34" + resolved "http://localhost:4873/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" + integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== + dependencies: + mime-db "1.51.0" + +mime@1.6.0: + version "1.6.0" + resolved "http://localhost:4873/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "http://localhost:4873/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +min-document@^2.19.0: + version "2.19.0" + resolved "http://localhost:4873/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= + dependencies: + dom-walk "^0.1.0" + +minimatch@^3.0.4: + version "3.0.4" + resolved "http://localhost:4873/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "http://localhost:4873/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +minipass@^2.6.0, minipass@^2.9.0: + version "2.9.0" + resolved "http://localhost:4873/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" + integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.3.3: + version "1.3.3" + resolved "http://localhost:4873/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" + integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== + dependencies: + minipass "^2.9.0" + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "http://localhost:4873/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.4, mkdirp@^0.5.5: + version "0.5.5" + resolved "http://localhost:4873/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +mkdirp@^1.0.4: + version "1.0.4" + resolved "http://localhost:4873/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +moment-timezone@^0.5.31: + version "0.5.34" + resolved "http://localhost:4873/moment-timezone/-/moment-timezone-0.5.34.tgz#a75938f7476b88f155d3504a9343f7519d9a405c" + integrity sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg== + dependencies: + moment ">= 2.9.0" + +"moment@>= 2.9.0": + version "2.29.1" + resolved "http://localhost:4873/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" + integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== + +morgan@^1.9.1: + version "1.10.0" + resolved "http://localhost:4873/morgan/-/morgan-1.10.0.tgz#091778abc1fc47cd3509824653dae1faab6b17d7" + integrity sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ== + dependencies: + basic-auth "~2.0.1" + debug "2.6.9" + depd "~2.0.0" + on-finished "~2.3.0" + on-headers "~1.0.2" + +ms@2.0.0: + version "2.0.0" + resolved "http://localhost:4873/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.2: + version "2.1.2" + resolved "http://localhost:4873/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3, ms@^2.1.1: + version "2.1.3" + resolved "http://localhost:4873/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multer@^1.4.2: + version "1.4.4" + resolved "http://localhost:4873/multer/-/multer-1.4.4.tgz#e2bc6cac0df57a8832b858d7418ccaa8ebaf7d8c" + integrity sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw== + dependencies: + append-field "^1.0.0" + busboy "^0.2.11" + concat-stream "^1.5.2" + mkdirp "^0.5.4" + object-assign "^4.1.1" + on-finished "^2.3.0" + type-is "^1.6.4" + xtend "^4.0.0" + +mute-stream@0.0.8: + version "0.0.8" + resolved "http://localhost:4873/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + +mz@^2.4.0: + version "2.7.0" + resolved "http://localhost:4873/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +nanomatch@^1.2.9: + version "1.2.13" + resolved "http://localhost:4873/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "http://localhost:4873/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +natural-orderby@^2.0.1: + version "2.0.3" + resolved "http://localhost:4873/natural-orderby/-/natural-orderby-2.0.3.tgz#8623bc518ba162f8ff1cdb8941d74deb0fdcc016" + integrity sha512-p7KTHxU0CUrcOXe62Zfrb5Z13nLvPhSWR/so3kFulUQU0sgUll2Z0LwpsLN351eOOD+hRGu/F1g+6xDfPeD++Q== + +needle@^2.2.1: + version "2.9.1" + resolved "http://localhost:4873/needle/-/needle-2.9.1.tgz#22d1dffbe3490c2b83e301f7709b6736cd8f2684" + integrity sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + +negotiator@0.6.2: + version "0.6.2" + resolved "http://localhost:4873/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +netrc-parser@^3.1.6: + version "3.1.6" + resolved "http://localhost:4873/netrc-parser/-/netrc-parser-3.1.6.tgz#7243c9ec850b8e805b9bdc7eae7b1450d4a96e72" + integrity sha512-lY+fmkqSwntAAjfP63jB4z5p5WbuZwyMCD3pInT7dpHU/Gc6Vv90SAC6A0aNiqaRGHiuZFBtiwu+pu8W/Eyotw== + dependencies: + debug "^3.1.0" + execa "^0.10.0" + +nice-try@^1.0.4: + version "1.0.5" + resolved "http://localhost:4873/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +no-case@^3.0.4: + version "3.0.4" + resolved "http://localhost:4873/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + +node-addon-api@^3.0.0: + version "3.2.1" + resolved "http://localhost:4873/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" + integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== + +node-environment-flags@^1.0.5: + version "1.0.6" + resolved "http://localhost:4873/node-environment-flags/-/node-environment-flags-1.0.6.tgz#a30ac13621f6f7d674260a54dede048c3982c088" + integrity sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw== + dependencies: + object.getownpropertydescriptors "^2.0.3" + semver "^5.7.0" + +node-gyp@3.x: + version "3.8.0" + resolved "http://localhost:4873/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c" + integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA== + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3 || 4" + osenv "0" + request "^2.87.0" + rimraf "2" + semver "~5.3.0" + tar "^2.0.0" + which "1" + +node-int64@^0.4.0: + version "0.4.0" + resolved "http://localhost:4873/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + +node-notifier@^8.0.0: + version "8.0.2" + resolved "http://localhost:4873/node-notifier/-/node-notifier-8.0.2.tgz#f3167a38ef0d2c8a866a83e318c1ba0efeb702c5" + integrity sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg== + dependencies: + growly "^1.3.0" + is-wsl "^2.2.0" + semver "^7.3.2" + shellwords "^0.1.1" + uuid "^8.3.0" + which "^2.0.2" + +node-pre-gyp@^0.11.0: + version "0.11.0" + resolved "http://localhost:4873/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054" + integrity sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + +node-releases@^2.0.1: + version "2.0.1" + resolved "http://localhost:4873/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" + integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== + +"nopt@2 || 3": + version "3.0.6" + resolved "http://localhost:4873/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= + dependencies: + abbrev "1" + +nopt@^4.0.1: + version "4.0.3" + resolved "http://localhost:4873/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" + integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.5.0: + version "2.5.0" + resolved "http://localhost:4873/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "http://localhost:4873/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "http://localhost:4873/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-bundled@^1.0.1: + version "1.1.2" + resolved "http://localhost:4873/npm-bundled/-/npm-bundled-1.1.2.tgz#944c78789bd739035b70baa2ca5cc32b8d860bc1" + integrity sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ== + dependencies: + npm-normalize-package-bin "^1.0.1" + +npm-normalize-package-bin@^1.0.1: + version "1.0.1" + resolved "http://localhost:4873/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" + integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== + +npm-packlist@^1.1.6: + version "1.4.8" + resolved "http://localhost:4873/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" + integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + npm-normalize-package-bin "^1.0.1" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "http://localhost:4873/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +npm-run-path@^4.0.0, npm-run-path@^4.0.1: + version "4.0.1" + resolved "http://localhost:4873/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.2: + version "4.1.2" + resolved "http://localhost:4873/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "http://localhost:4873/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +nwsapi@^2.2.0: + version "2.2.0" + resolved "http://localhost:4873/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "http://localhost:4873/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "http://localhost:4873/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-copy@^0.1.0: + version "0.1.0" + resolved "http://localhost:4873/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@^1.11.0, object-inspect@^1.9.0: + version "1.12.0" + resolved "http://localhost:4873/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" + integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== + +object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "http://localhost:4873/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object-treeify@^1.1.4: + version "1.1.33" + resolved "http://localhost:4873/object-treeify/-/object-treeify-1.1.33.tgz#f06fece986830a3cba78ddd32d4c11d1f76cdf40" + integrity sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A== + +object-visit@^1.0.0: + version "1.0.1" + resolved "http://localhost:4873/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.assign@^4.1.0, object.assign@^4.1.2: + version "4.1.2" + resolved "http://localhost:4873/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.1: + version "2.1.3" + resolved "http://localhost:4873/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz#b223cf38e17fefb97a63c10c91df72ccb386df9e" + integrity sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +object.pick@^1.3.0: + version "1.3.0" + resolved "http://localhost:4873/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +on-finished@^2.3.0, on-finished@~2.3.0: + version "2.3.0" + resolved "http://localhost:4873/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "http://localhost:4873/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "http://localhost:4873/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +one-time@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45" + integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== + dependencies: + fn.name "1.x.x" + +onetime@^5.1.0, onetime@^5.1.2: + version "5.1.2" + resolved "http://localhost:4873/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +open@^8.0.6: + version "8.4.0" + resolved "http://localhost:4873/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" + integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + +optionator@^0.8.1: + version "0.8.3" + resolved "http://localhost:4873/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +ora@^5.4.1: + version "5.4.1" + resolved "http://localhost:4873/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" + integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== + dependencies: + bl "^4.1.0" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.5.0" + is-interactive "^1.0.0" + is-unicode-supported "^0.1.0" + log-symbols "^4.1.0" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + +os-homedir@^1.0.0: + version "1.0.2" + resolved "http://localhost:4873/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: + version "1.0.2" + resolved "http://localhost:4873/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +osenv@0, osenv@^0.1.4: + version "0.1.5" + resolved "http://localhost:4873/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-each-series@^2.1.0: + version "2.2.0" + resolved "http://localhost:4873/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a" + integrity sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA== + +p-finally@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-limit@^2.0.0, p-limit@^2.2.0: + version "2.3.0" + resolved "http://localhost:4873/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "http://localhost:4873/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "http://localhost:4873/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-map@^2.1.0: + version "2.1.0" + resolved "http://localhost:4873/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + +p-timeout@^3.2.0: + version "3.2.0" + resolved "http://localhost:4873/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" + integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== + dependencies: + p-finally "^1.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "http://localhost:4873/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +packet-reader@1.0.0: + version "1.0.0" + resolved "http://localhost:4873/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" + integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== + +parse-json@^5.0.0: + version "5.2.0" + resolved "http://localhost:4873/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parse-passwd@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= + +parse5-htmlparser2-tree-adapter@^6.0.0: + version "6.0.1" + resolved "http://localhost:4873/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" + integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== + dependencies: + parse5 "^6.0.1" + +parse5@6.0.1, parse5@^6.0.1: + version "6.0.1" + resolved "http://localhost:4873/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + +parse5@^5.1.1: + version "5.1.1" + resolved "http://localhost:4873/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" + integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== + +parseurl@~1.3.3: + version "1.3.3" + resolved "http://localhost:4873/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascal-case@^3.1.2: + version "3.1.2" + resolved "http://localhost:4873/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" + integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +pascalcase@^0.1.1: + version "0.1.1" + resolved "http://localhost:4873/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +passport-http-bearer@^1.0.1: + version "1.0.1" + resolved "http://localhost:4873/passport-http-bearer/-/passport-http-bearer-1.0.1.tgz#147469ea3669e2a84c6167ef99dbb77e1f0098a8" + integrity sha1-FHRp6jZp4qhMYWfvmdu3fh8AmKg= + dependencies: + passport-strategy "1.x.x" + +passport-jwt@^4.0.0: + version "4.0.0" + resolved "http://localhost:4873/passport-jwt/-/passport-jwt-4.0.0.tgz#7f0be7ba942e28b9f5d22c2ebbb8ce96ef7cf065" + integrity sha512-BwC0n2GP/1hMVjR4QpnvqA61TxenUMlmfNjYNgK0ZAs0HK4SOQkHcSv4L328blNTLtHq7DbmvyNJiH+bn6C5Mg== + dependencies: + jsonwebtoken "^8.2.0" + passport-strategy "^1.0.0" + +passport-local@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/passport-local/-/passport-local-1.0.0.tgz#1fe63268c92e75606626437e3b906662c15ba6ee" + integrity sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4= + dependencies: + passport-strategy "1.x.x" + +passport-strategy@1.x.x, passport-strategy@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" + integrity sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ= + +passport@^0.4.0: + version "0.4.1" + resolved "http://localhost:4873/passport/-/passport-0.4.1.tgz#941446a21cb92fc688d97a0861c38ce9f738f270" + integrity sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg== + dependencies: + passport-strategy "1.x.x" + pause "0.0.1" + +password-prompt@^1.1.2: + version "1.1.2" + resolved "http://localhost:4873/password-prompt/-/password-prompt-1.1.2.tgz#85b2f93896c5bd9e9f2d6ff0627fa5af3dc00923" + integrity sha512-bpuBhROdrhuN3E7G/koAju0WjVw9/uQOG5Co5mokNj0MiOSBVZS1JTwM4zl55hu0WFmIEFvO9cU9sJQiBIYeIA== + dependencies: + ansi-escapes "^3.1.0" + cross-spawn "^6.0.5" + +path-exists@^3.0.0: + version "3.0.0" + resolved "http://localhost:4873/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-exists@^4.0.0: + version "4.0.0" + resolved "http://localhost:4873/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "http://localhost:4873/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "http://localhost:4873/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "http://localhost:4873/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "http://localhost:4873/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "http://localhost:4873/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + +path-type@^4.0.0: + version "4.0.0" + resolved "http://localhost:4873/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pause@0.0.1: + version "0.0.1" + resolved "http://localhost:4873/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" + integrity sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10= + +performance-now@^2.1.0: + version "2.1.0" + resolved "http://localhost:4873/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +pg-connection-string@^2.5.0: + version "2.5.0" + resolved "http://localhost:4873/pg-connection-string/-/pg-connection-string-2.5.0.tgz#538cadd0f7e603fc09a12590f3b8a452c2c0cf34" + integrity sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ== + +pg-god@^1.0.11: + version "1.0.11" + resolved "http://localhost:4873/pg-god/-/pg-god-1.0.11.tgz#5bc73a5ccb0fc5b439177462d9712ef4d1b83c9a" + integrity sha512-bW14qUfEt3jDruac0Pq9O1Pi6vH5cgLKVx3l8IdBrJS7GX0wBS4b6rlfTrU8373MCAXauP6x8VkD0rNE3mTxCw== + dependencies: + "@oclif/command" "^1" + "@oclif/config" "^1" + "@oclif/plugin-help" "^3" + cli-ux "^5.4.9" + pg "^8.3.0" + tslib "^1" + +pg-int8@1.0.1: + version "1.0.1" + resolved "http://localhost:4873/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" + integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== + +pg-pool@^3.4.1: + version "3.4.1" + resolved "http://localhost:4873/pg-pool/-/pg-pool-3.4.1.tgz#0e71ce2c67b442a5e862a9c182172c37eda71e9c" + integrity sha512-TVHxR/gf3MeJRvchgNHxsYsTCHQ+4wm3VIHSS19z8NC0+gioEhq1okDY1sm/TYbfoP6JLFx01s0ShvZ3puP/iQ== + +pg-protocol@^1.5.0: + version "1.5.0" + resolved "http://localhost:4873/pg-protocol/-/pg-protocol-1.5.0.tgz#b5dd452257314565e2d54ab3c132adc46565a6a0" + integrity sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ== + +pg-types@^2.1.0: + version "2.2.0" + resolved "http://localhost:4873/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" + integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== + dependencies: + pg-int8 "1.0.1" + postgres-array "~2.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.4" + postgres-interval "^1.1.0" + +pg@^8.3.0, pg@^8.5.1: + version "8.7.1" + resolved "http://localhost:4873/pg/-/pg-8.7.1.tgz#9ea9d1ec225980c36f94e181d009ab9f4ce4c471" + integrity sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA== + dependencies: + buffer-writer "2.0.0" + packet-reader "1.0.0" + pg-connection-string "^2.5.0" + pg-pool "^3.4.1" + pg-protocol "^1.5.0" + pg-types "^2.1.0" + pgpass "1.x" + +pgpass@1.x: + version "1.0.5" + resolved "http://localhost:4873/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d" + integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug== + dependencies: + split2 "^4.1.0" + +picocolors@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: + version "2.3.1" + resolved "http://localhost:4873/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pify@^4.0.1: + version "4.0.1" + resolved "http://localhost:4873/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pirates@^4.0.0, pirates@^4.0.1: + version "4.0.4" + resolved "http://localhost:4873/pirates/-/pirates-4.0.4.tgz#07df81e61028e402735cdd49db701e4885b4e6e6" + integrity sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw== + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "http://localhost:4873/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "http://localhost:4873/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "http://localhost:4873/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +postgres-array@~2.0.0: + version "2.0.0" + resolved "http://localhost:4873/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" + integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== + +postgres-bytea@~1.0.0: + version "1.0.0" + resolved "http://localhost:4873/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" + integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU= + +postgres-date@~1.0.4: + version "1.0.7" + resolved "http://localhost:4873/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" + integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== + +postgres-interval@^1.1.0: + version "1.2.0" + resolved "http://localhost:4873/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" + integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== + dependencies: + xtend "^4.0.0" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "http://localhost:4873/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +pretty-format@^26.6.2: + version "26.6.2" + resolved "http://localhost:4873/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" + integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== + dependencies: + "@jest/types" "^26.6.2" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^17.0.1" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "http://localhost:4873/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process@^0.11.10: + version "0.11.10" + resolved "http://localhost:4873/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + +promise.prototype.finally@^3.1.2: + version "3.1.3" + resolved "http://localhost:4873/promise.prototype.finally/-/promise.prototype.finally-3.1.3.tgz#d3186e58fcf4df1682a150f934ccc27b7893389c" + integrity sha512-EXRF3fC9/0gz4qkt/f5EP5iW4kj9oFpBICNpCNOb/52+8nlHIX07FPLbi/q4qYBQ1xZqivMzTpNQSnArVASolQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + +prompts@^2.0.1, prompts@^2.4.1: + version "2.4.2" + resolved "http://localhost:4873/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "http://localhost:4873/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +psl@^1.1.28, psl@^1.1.33: + version "1.8.0" + resolved "http://localhost:4873/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + +pump@^3.0.0: + version "3.0.0" + resolved "http://localhost:4873/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@1.3.2: + version "1.3.2" + resolved "http://localhost:4873/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "http://localhost:4873/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +qs@6.9.6: + version "6.9.6" + resolved "http://localhost:4873/qs/-/qs-6.9.6.tgz#26ed3c8243a431b2924aca84cc90471f35d5a0ee" + integrity sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ== + +qs@~6.5.2: + version "6.5.3" + resolved "http://localhost:4873/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" + integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== + +querystring@0.2.0: + version "0.2.0" + resolved "http://localhost:4873/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "http://localhost:4873/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +random-bytes@~1.0.0: + version "1.0.0" + resolved "http://localhost:4873/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" + integrity sha1-T2ih3Arli9P7lYSMMDJNt11kNgs= + +randomatic@^3.1.1: + version "3.1.1" + resolved "http://localhost:4873/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed" + integrity sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw== + dependencies: + is-number "^4.0.0" + kind-of "^6.0.0" + math-random "^1.0.1" + +range-parser@~1.2.1: + version "1.2.1" + resolved "http://localhost:4873/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.4.2: + version "2.4.2" + resolved "http://localhost:4873/raw-body/-/raw-body-2.4.2.tgz#baf3e9c21eebced59dd6533ac872b71f7b61cb32" + integrity sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ== + dependencies: + bytes "3.1.1" + http-errors "1.8.1" + iconv-lite "0.4.24" + unpipe "1.0.0" + +rc@^1.2.7: + version "1.2.8" + resolved "http://localhost:4873/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +react-is@^17.0.1: + version "17.0.2" + resolved "http://localhost:4873/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + +read-pkg-up@^7.0.1: + version "7.0.1" + resolved "http://localhost:4873/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" + integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== + dependencies: + find-up "^4.1.0" + read-pkg "^5.2.0" + type-fest "^0.8.1" + +read-pkg@^5.2.0: + version "5.2.0" + resolved "http://localhost:4873/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^2.5.0" + parse-json "^5.0.0" + type-fest "^0.6.0" + +readable-stream@1.1.x: + version "1.1.14" + resolved "http://localhost:4873/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^2.0.6, readable-stream@^2.2.2: + version "2.3.7" + resolved "http://localhost:4873/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.4.0: + version "3.6.0" + resolved "http://localhost:4873/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "http://localhost:4873/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +readline-sync@^1.4.9: + version "1.4.10" + resolved "http://localhost:4873/readline-sync/-/readline-sync-1.4.10.tgz#41df7fbb4b6312d673011594145705bf56d8873b" + integrity sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw== + +redeyed@~2.1.0: + version "2.1.1" + resolved "http://localhost:4873/redeyed/-/redeyed-2.1.1.tgz#8984b5815d99cb220469c99eeeffe38913e6cc0b" + integrity sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs= + dependencies: + esprima "~4.0.0" + +redis-commands@1.7.0, redis-commands@^1.7.0: + version "1.7.0" + resolved "http://localhost:4873/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" + integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ== + +redis-errors@^1.0.0, redis-errors@^1.2.0: + version "1.2.0" + resolved "http://localhost:4873/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= + +redis-parser@^3.0.0: + version "3.0.0" + resolved "http://localhost:4873/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= + dependencies: + redis-errors "^1.0.0" + +redis@^3.0.2: + version "3.1.2" + resolved "http://localhost:4873/redis/-/redis-3.1.2.tgz#766851117e80653d23e0ed536254677ab647638c" + integrity sha512-grn5KoZLr/qrRQVwoSkmzdbw6pwF+/rwODtrOr6vuBRiR/f3rjSTGupbF90Zpqm2oenix8Do6RV7pYEkGwlKkw== + dependencies: + denque "^1.5.0" + redis-commands "^1.7.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + +reflect-metadata@^0.1.13: + version "0.1.13" + resolved "http://localhost:4873/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" + integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== + +regenerate-unicode-properties@^9.0.0: + version "9.0.0" + resolved "http://localhost:4873/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326" + integrity sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "http://localhost:4873/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.5: + version "0.13.9" + resolved "http://localhost:4873/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +regenerator-transform@^0.14.2: + version "0.14.5" + resolved "http://localhost:4873/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" + integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== + dependencies: + "@babel/runtime" "^7.8.4" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "http://localhost:4873/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexpu-core@^4.7.1: + version "4.8.0" + resolved "http://localhost:4873/regexpu-core/-/regexpu-core-4.8.0.tgz#e5605ba361b67b1718478501327502f4479a98f0" + integrity sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg== + dependencies: + regenerate "^1.4.2" + regenerate-unicode-properties "^9.0.0" + regjsgen "^0.5.2" + regjsparser "^0.7.0" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.0.0" + +regjsgen@^0.5.2: + version "0.5.2" + resolved "http://localhost:4873/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" + integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== + +regjsparser@^0.7.0: + version "0.7.0" + resolved "http://localhost:4873/regjsparser/-/regjsparser-0.7.0.tgz#a6b667b54c885e18b52554cb4960ef71187e9968" + integrity sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ== + dependencies: + jsesc "~0.5.0" + +remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "http://localhost:4873/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +remove-trailing-slash@^0.1.1: + version "0.1.1" + resolved "http://localhost:4873/remove-trailing-slash/-/remove-trailing-slash-0.1.1.tgz#be2285a59f39c74d1bce4f825950061915e3780d" + integrity sha512-o4S4Qh6L2jpnCy83ysZDau+VORNvnFw07CKSAymkd6ICNVEPisMyzlc00KlvvicsxKck94SEwhDnMNdICzO+tA== + +repeat-element@^1.1.2: + version "1.1.4" + resolved "http://localhost:4873/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "http://localhost:4873/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +request-ip@^2.1.3: + version "2.1.3" + resolved "http://localhost:4873/request-ip/-/request-ip-2.1.3.tgz#99ab2bafdeaf2002626e28083cb10597511d9e14" + integrity sha512-J3qdE/IhVM3BXkwMIVO4yFrvhJlU3H7JH16+6yHucadT4fePnR8dyh+vEs6FIx0S2x5TCt2ptiPfHcn0sqhbYQ== + dependencies: + is_js "^0.9.0" + +request@^2.87.0: + version "2.88.2" + resolved "http://localhost:4873/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +require-directory@^2.1.1: + version "2.1.1" + resolved "http://localhost:4873/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "http://localhost:4873/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^5.0.0: + version "5.0.0" + resolved "http://localhost:4873/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve-url@^0.2.1: + version "0.2.1" + resolved "http://localhost:4873/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@^1.10.0, resolve@^1.14.2, resolve@^1.18.1: + version "1.21.0" + resolved "http://localhost:4873/resolve/-/resolve-1.21.0.tgz#b51adc97f3472e6a5cf4444d34bc9d6b9037591f" + integrity sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA== + dependencies: + is-core-module "^2.8.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "http://localhost:4873/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +ret@~0.1.10: + version "0.1.15" + resolved "http://localhost:4873/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +reusify@^1.0.4: + version "1.0.4" + resolved "http://localhost:4873/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@2, rimraf@^2.6.1: + version "2.7.1" + resolved "http://localhost:4873/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.0: + version "3.0.2" + resolved "http://localhost:4873/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rsvp@^4.8.4: + version "4.8.5" + resolved "http://localhost:4873/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" + integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== + +run-async@^2.4.0: + version "2.4.1" + resolved "http://localhost:4873/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +run-parallel@^1.1.9: + version "1.2.0" + resolved "http://localhost:4873/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +rxjs@^7.2.0: + version "7.5.2" + resolved "http://localhost:4873/rxjs/-/rxjs-7.5.2.tgz#11e4a3a1dfad85dbf7fb6e33cbba17668497490b" + integrity sha512-PwDt186XaL3QN5qXj/H9DGyHhP3/RYYgZZwqBv9Tv8rsAaiwFH1IsJJlcgD37J7UW5a6O67qX0KWKS3/pu0m4w== + dependencies: + tslib "^2.1.0" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "http://localhost:4873/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@^5.2.1, safe-buffer@~5.2.0: + version "5.2.1" + resolved "http://localhost:4873/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-regex@^1.1.0: + version "1.1.0" + resolved "http://localhost:4873/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +safe-stable-stringify@^1.1.0: + version "1.1.1" + resolved "http://localhost:4873/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz#c8a220ab525cd94e60ebf47ddc404d610dc5d84a" + integrity sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw== + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "http://localhost:4873/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sane@^4.0.3: + version "4.1.0" + resolved "http://localhost:4873/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" + integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== + dependencies: + "@cnakazawa/watch" "^1.0.3" + anymatch "^2.0.0" + capture-exit "^2.0.0" + exec-sh "^0.3.2" + execa "^1.0.0" + fb-watchman "^2.0.0" + micromatch "^3.1.4" + minimist "^1.1.1" + walker "~1.0.5" + +sax@>=0.6.0, sax@^1.2.4: + version "1.2.4" + resolved "http://localhost:4873/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + +saxes@^5.0.1: + version "5.0.1" + resolved "http://localhost:4873/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" + +scrypt-kdf@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/scrypt-kdf/-/scrypt-kdf-2.0.1.tgz#3355224c52d398331b2cbf2b70a7be26b52c53e6" + integrity sha512-dMhpgBVJPDWZP5erOCwTjI6oAO9hKhFAjZsdSQ0spaWJYHuA/wFNF2weQQfsyCIk8eNKoLfEDxr3zAtM+gZo0Q== + +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0: + version "5.7.1" + resolved "http://localhost:4873/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@7.0.0: + version "7.0.0" + resolved "http://localhost:4873/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: + version "6.3.0" + resolved "http://localhost:4873/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.3.2: + version "7.3.5" + resolved "http://localhost:4873/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + +semver@~5.3.0: + version "5.3.0" + resolved "http://localhost:4873/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= + +send@0.17.2: + version "0.17.2" + resolved "http://localhost:4873/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820" + integrity sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "1.8.1" + mime "1.6.0" + ms "2.1.3" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serve-static@1.14.2: + version "1.14.2" + resolved "http://localhost:4873/serve-static/-/serve-static-1.14.2.tgz#722d6294b1d62626d41b43a013ece4598d292bfa" + integrity sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.2" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "http://localhost:4873/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "http://localhost:4873/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +setprototypeof@1.2.0: + version "1.2.0" + resolved "http://localhost:4873/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +sha.js@^2.4.11: + version "2.4.11" + resolved "http://localhost:4873/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "http://localhost:4873/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "http://localhost:4873/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "http://localhost:4873/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shellwords@^0.1.1: + version "0.1.1" + resolved "http://localhost:4873/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== + +side-channel@^1.0.4: + version "1.0.4" + resolved "http://localhost:4873/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: + version "3.0.6" + resolved "http://localhost:4873/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" + integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "http://localhost:4873/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + +sisteransi@^1.0.5: + version "1.0.5" + resolved "http://localhost:4873/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + +slash@^3.0.0: + version "3.0.0" + resolved "http://localhost:4873/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "http://localhost:4873/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "http://localhost:4873/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "http://localhost:4873/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + +source-map-resolve@^0.5.0: + version "0.5.3" + resolved "http://localhost:4873/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@^0.5.16, source-map-support@^0.5.6: + version "0.5.21" + resolved "http://localhost:4873/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.1" + resolved "http://localhost:4873/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" + integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== + +source-map@^0.5.0, source-map@^0.5.6: + version "0.5.7" + resolved "http://localhost:4873/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "http://localhost:4873/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.7.3: + version "0.7.3" + resolved "http://localhost:4873/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + +spdx-correct@^3.0.0: + version "3.1.1" + resolved "http://localhost:4873/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "http://localhost:4873/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "http://localhost:4873/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.11" + resolved "http://localhost:4873/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95" + integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g== + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "http://localhost:4873/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +split2@^4.1.0: + version "4.1.0" + resolved "http://localhost:4873/split2/-/split2-4.1.0.tgz#101907a24370f85bb782f08adaabe4e281ecf809" + integrity sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ== + +sprintf-js@^1.1.1: + version "1.1.2" + resolved "http://localhost:4873/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" + integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "http://localhost:4873/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +sqlite3@^5.0.2: + version "5.0.2" + resolved "http://localhost:4873/sqlite3/-/sqlite3-5.0.2.tgz#00924adcc001c17686e0a6643b6cbbc2d3965083" + integrity sha512-1SdTNo+BVU211Xj1csWa8lV6KM0CtucDwRyA0VHl91wEH1Mgh7RxUpI4rVvG7OhHrzCSGaVyW5g8vKvlrk9DJA== + dependencies: + node-addon-api "^3.0.0" + node-pre-gyp "^0.11.0" + optionalDependencies: + node-gyp "3.x" + +sshpk@^1.7.0: + version "1.17.0" + resolved "http://localhost:4873/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" + integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +stack-trace@0.0.x, stack-trace@^0.0.10: + version "0.0.10" + resolved "http://localhost:4873/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= + +stack-utils@^2.0.2: + version "2.0.5" + resolved "http://localhost:4873/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" + integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== + dependencies: + escape-string-regexp "^2.0.0" + +standard-as-callback@^2.1.0: + version "2.1.0" + resolved "http://localhost:4873/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" + integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== + +static-extend@^0.1.1: + version "0.1.2" + resolved "http://localhost:4873/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "http://localhost:4873/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +streamsearch@0.1.2: + version "0.1.2" + resolved "http://localhost:4873/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" + integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo= + +string-length@^4.0.1: + version "4.0.2" + resolved "http://localhost:4873/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^1.0.1: + version "1.0.2" + resolved "http://localhost:4873/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: + version "4.2.3" + resolved "http://localhost:4873/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "http://localhost:4873/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "http://localhost:4873/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "http://localhost:4873/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "http://localhost:4873/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + +string_decoder@~1.1.1: + version "1.1.1" + resolved "http://localhost:4873/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "http://localhost:4873/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "http://localhost:4873/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^4.0.0: + version "4.0.0" + resolved "http://localhost:4873/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-eof@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "http://localhost:4873/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= + +supports-color@^5.3.0: + version "5.5.0" + resolved "http://localhost:4873/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "http://localhost:4873/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.1.0: + version "8.1.1" + resolved "http://localhost:4873/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^2.0.0, supports-hyperlinks@^2.1.0: + version "2.2.0" + resolved "http://localhost:4873/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +symbol-tree@^3.2.4: + version "3.2.4" + resolved "http://localhost:4873/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + +tar@^2.0.0: + version "2.2.2" + resolved "http://localhost:4873/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40" + integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA== + dependencies: + block-stream "*" + fstream "^1.0.12" + inherits "2" + +tar@^4: + version "4.4.19" + resolved "http://localhost:4873/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3" + integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA== + dependencies: + chownr "^1.1.4" + fs-minipass "^1.2.7" + minipass "^2.9.0" + minizlib "^1.3.3" + mkdirp "^0.5.5" + safe-buffer "^5.2.1" + yallist "^3.1.1" + +terminal-link@^2.0.0: + version "2.1.1" + resolved "http://localhost:4873/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "http://localhost:4873/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-hex@1.0.x: + version "1.0.0" + resolved "http://localhost:4873/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" + integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== + +thenify-all@^1.0.0: + version "1.6.0" + resolved "http://localhost:4873/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "http://localhost:4873/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + +throat@^5.0.0: + version "5.0.0" + resolved "http://localhost:4873/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" + integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== + +through@^2.3.6: + version "2.3.8" + resolved "http://localhost:4873/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +tmp@^0.0.33: + version "0.0.33" + resolved "http://localhost:4873/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +tmpl@1.0.5: + version "1.0.5" + resolved "http://localhost:4873/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "http://localhost:4873/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "http://localhost:4873/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "http://localhost:4873/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "http://localhost:4873/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "http://localhost:4873/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +tough-cookie@^4.0.0: + version "4.0.0" + resolved "http://localhost:4873/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" + integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.1.2" + +tough-cookie@~2.5.0: + version "2.5.0" + resolved "http://localhost:4873/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +tr46@^2.1.0: + version "2.1.0" + resolved "http://localhost:4873/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== + dependencies: + punycode "^2.1.1" + +triple-beam@^1.2.0, triple-beam@^1.3.0: + version "1.3.0" + resolved "http://localhost:4873/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" + integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== + +tslib@^1: + version "1.14.1" + resolved "http://localhost:4873/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0: + version "2.3.1" + resolved "http://localhost:4873/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "http://localhost:4873/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "http://localhost:4873/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-check@~0.3.2: + version "0.3.2" + resolved "http://localhost:4873/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-detect@4.0.8: + version "4.0.8" + resolved "http://localhost:4873/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.20.2: + version "0.20.2" + resolved "http://localhost:4873/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "http://localhost:4873/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^0.6.0: + version "0.6.0" + resolved "http://localhost:4873/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== + +type-fest@^0.8.1: + version "0.8.1" + resolved "http://localhost:4873/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +type-is@^1.6.4, type-is@~1.6.18: + version "1.6.18" + resolved "http://localhost:4873/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "http://localhost:4873/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +typedarray@^0.0.6: + version "0.0.6" + resolved "http://localhost:4873/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +typeorm@^0.2.31: + version "0.2.41" + resolved "http://localhost:4873/typeorm/-/typeorm-0.2.41.tgz#88758101ac158dc0a0a903d70eaacea2974281cc" + integrity sha512-/d8CLJJxKPgsnrZWiMyPI0rz2MFZnBQrnQ5XP3Vu3mswv2WPexb58QM6BEtmRmlTMYN5KFWUz8SKluze+wS9xw== + dependencies: + "@sqltools/formatter" "^1.2.2" + app-root-path "^3.0.0" + buffer "^6.0.3" + chalk "^4.1.0" + cli-highlight "^2.1.11" + debug "^4.3.1" + dotenv "^8.2.0" + glob "^7.1.6" + js-yaml "^4.0.0" + mkdirp "^1.0.4" + reflect-metadata "^0.1.13" + sha.js "^2.4.11" + tslib "^2.1.0" + xml2js "^0.4.23" + yargs "^17.0.1" + zen-observable-ts "^1.0.0" + +uid-safe@~2.1.5: + version "2.1.5" + resolved "http://localhost:4873/uid-safe/-/uid-safe-2.1.5.tgz#2b3d5c7240e8fc2e58f8aa269e5ee49c0857bd3a" + integrity sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA== + dependencies: + random-bytes "~1.0.0" + +ulid@^2.3.0: + version "2.3.0" + resolved "http://localhost:4873/ulid/-/ulid-2.3.0.tgz#93063522771a9774121a84d126ecd3eb9804071f" + integrity sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw== + +unbox-primitive@^1.0.1: + version "1.0.1" + resolved "http://localhost:4873/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" + integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" + integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== + +union-value@^1.0.0: + version "1.0.1" + resolved "http://localhost:4873/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +unique-string@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" + integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== + dependencies: + crypto-random-string "^2.0.0" + +universalify@^0.1.0, universalify@^0.1.2: + version "0.1.2" + resolved "http://localhost:4873/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +universalify@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "http://localhost:4873/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unset-value@^1.0.0: + version "1.0.0" + resolved "http://localhost:4873/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "http://localhost:4873/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "http://localhost:4873/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url@^0.11.0: + version "0.11.0" + resolved "http://localhost:4873/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "http://localhost:4873/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "http://localhost:4873/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util.promisify@^1.0.1: + version "1.1.1" + resolved "http://localhost:4873/util.promisify/-/util.promisify-1.1.1.tgz#77832f57ced2c9478174149cae9b96e9918cd54b" + integrity sha512-/s3UsZUrIfa6xDhr7zZhnE9SLQ5RIXyYfiVnMMyMDzOc8WhWN4Nbh36H842OyurKbCDAesZOJaVyvmSl6fhGQw== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + for-each "^0.3.3" + has-symbols "^1.0.1" + object.getownpropertydescriptors "^2.1.1" + +utils-merge@1.0.1: + version "1.0.1" + resolved "http://localhost:4873/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^3.3.2: + version "3.4.0" + resolved "http://localhost:4873/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +uuid@^8.3.0, uuid@^8.3.1, uuid@^8.3.2: + version "8.3.2" + resolved "http://localhost:4873/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +v8-to-istanbul@^7.0.0: + version "7.1.2" + resolved "http://localhost:4873/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz#30898d1a7fa0c84d225a2c1434fb958f290883c1" + integrity sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + source-map "^0.7.3" + +v8flags@^3.1.1: + version "3.2.0" + resolved "http://localhost:4873/v8flags/-/v8flags-3.2.0.tgz#b243e3b4dfd731fa774e7492128109a0fe66d656" + integrity sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg== + dependencies: + homedir-polyfill "^1.0.1" + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "http://localhost:4873/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +validator@^13.7.0: + version "13.7.0" + resolved "http://localhost:4873/validator/-/validator-13.7.0.tgz#4f9658ba13ba8f3d82ee881d3516489ea85c0857" + integrity sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw== + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "http://localhost:4873/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + +verror@1.10.0: + version "1.10.0" + resolved "http://localhost:4873/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +w3c-hr-time@^1.0.2: + version "1.0.2" + resolved "http://localhost:4873/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + +w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== + dependencies: + xml-name-validator "^3.0.0" + +walker@^1.0.7, walker@~1.0.5: + version "1.0.8" + resolved "http://localhost:4873/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +wcwidth@^1.0.1: + version "1.0.1" + resolved "http://localhost:4873/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + dependencies: + defaults "^1.0.3" + +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "http://localhost:4873/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== + +webidl-conversions@^6.1.0: + version "6.1.0" + resolved "http://localhost:4873/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== + +whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "http://localhost:4873/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-mimetype@^2.3.0: + version "2.3.0" + resolved "http://localhost:4873/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^8.0.0, whatwg-url@^8.5.0: + version "8.7.0" + resolved "http://localhost:4873/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" + integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== + dependencies: + lodash "^4.7.0" + tr46 "^2.1.0" + webidl-conversions "^6.1.0" + +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "http://localhost:4873/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-module@^2.0.0: + version "2.0.0" + resolved "http://localhost:4873/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which@1, which@^1.2.9: + version "1.3.1" + resolved "http://localhost:4873/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1, which@^2.0.2: + version "2.0.2" + resolved "http://localhost:4873/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.5" + resolved "http://localhost:4873/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== + dependencies: + string-width "^1.0.2 || 2 || 3 || 4" + +widest-line@^3.1.0: + version "3.1.0" + resolved "http://localhost:4873/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" + integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== + dependencies: + string-width "^4.0.0" + +winston-transport@^4.4.2: + version "4.4.2" + resolved "http://localhost:4873/winston-transport/-/winston-transport-4.4.2.tgz#554efe3fce229d046df006e0e3c411d240652e51" + integrity sha512-9jmhltAr5ygt5usgUTQbEiw/7RYXpyUbEAFRCSicIacpUzPkrnQsQZSPGEI12aLK9Jth4zNcYJx3Cvznwrl8pw== + dependencies: + logform "^2.3.2" + readable-stream "^3.4.0" + triple-beam "^1.2.0" + +winston@^3.2.1, winston@^3.3.3: + version "3.4.0" + resolved "http://localhost:4873/winston/-/winston-3.4.0.tgz#7080f24b02a0684f8a37f9d5c6afb1ac23e95b84" + integrity sha512-FqilVj+5HKwCfIHQzMxrrd5tBIH10JTS3koFGbLVWBODjiIYq7zir08rFyBT4rrTYG/eaTqDcfSIbcjSM78YSw== + dependencies: + "@dabh/diagnostics" "^2.0.2" + async "^3.2.3" + is-stream "^2.0.0" + logform "^2.3.2" + one-time "^1.0.0" + readable-stream "^3.4.0" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.4.2" + +word-wrap@~1.2.3: + version "1.2.3" + resolved "http://localhost:4873/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "http://localhost:4873/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "http://localhost:4873/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "http://localhost:4873/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "http://localhost:4873/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +ws@^7.4.6: + version "7.5.6" + resolved "http://localhost:4873/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b" + integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA== + +xdg-basedir@^4.0.0: + version "4.0.0" + resolved "http://localhost:4873/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" + integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "http://localhost:4873/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + +xml2js@^0.4.23: + version "0.4.23" + resolved "http://localhost:4873/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" + integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + +xmlbuilder@~11.0.0: + version "11.0.1" + resolved "http://localhost:4873/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== + +xmlchars@^2.2.0: + version "2.2.0" + resolved "http://localhost:4873/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + +xtend@^4.0.0: + version "4.0.2" + resolved "http://localhost:4873/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^4.0.0: + version "4.0.3" + resolved "http://localhost:4873/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "http://localhost:4873/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.0, yallist@^3.1.1: + version "3.1.1" + resolved "http://localhost:4873/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "http://localhost:4873/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@^18.1.2: + version "18.1.3" + resolved "http://localhost:4873/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "http://localhost:4873/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-parser@^21.0.0: + version "21.0.0" + resolved "http://localhost:4873/yargs-parser/-/yargs-parser-21.0.0.tgz#a485d3966be4317426dd56bdb6a30131b281dc55" + integrity sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA== + +yargs@^15.3.1, yargs@^15.4.1: + version "15.4.1" + resolved "http://localhost:4873/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^18.1.2" + +yargs@^16.0.0: + version "16.2.0" + resolved "http://localhost:4873/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yargs@^17.0.1: + version "17.3.1" + resolved "http://localhost:4873/yargs/-/yargs-17.3.1.tgz#da56b28f32e2fd45aefb402ed9c26f42be4c07b9" + integrity sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.0.0" + +zen-observable-ts@^1.0.0: + version "1.1.0" + resolved "http://localhost:4873/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz#2d1aa9d79b87058e9b75698b92791c1838551f83" + integrity sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA== + dependencies: + "@types/zen-observable" "0.8.3" + zen-observable "0.8.15" + +zen-observable@0.8.15: + version "0.8.15" + resolved "http://localhost:4873/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" + integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== diff --git a/integration-tests/yarn.lock b/integration-tests/yarn.lock new file mode 100644 index 0000000000..1fd8e97b7f --- /dev/null +++ b/integration-tests/yarn.lock @@ -0,0 +1,13 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@faker-js/faker@^5.5.3": + version "5.5.3" + resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-5.5.3.tgz#18e3af6b8eae7984072bbeb0c0858474d7c4cefe" + integrity sha512-R11tGE6yIFwqpaIqcfkcg7AICXzFg14+5h5v0TfF/9+RMDL6jhzCy/pxHVOfbALGdtVYdt6JdR21tuxEgl34dw== + +dotenv@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" + integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== diff --git a/packages/medusa-cli/src/reporter/index.js b/packages/medusa-cli/src/reporter/index.js index 7493deeec6..db87c6b4f9 100644 --- a/packages/medusa-cli/src/reporter/index.js +++ b/packages/medusa-cli/src/reporter/index.js @@ -45,7 +45,7 @@ export class Reporter { this.ora_ = activityLogger } - panic = data => { + panic = (data) => { const parsedPanic = panicHandler(data) this.loggerInstance_.log({ @@ -66,7 +66,7 @@ export class Reporter { * @param {string} level - the level to check if logger is configured for * @return {boolean} whether we should log */ - shouldLog = level => { + shouldLog = (level) => { level = this.loggerInstance_.levels[level] const logLevel = this.loggerInstance_.levels[this.loggerInstance_.level] return level <= logLevel @@ -76,7 +76,7 @@ export class Reporter { * Sets the log level of the logger. * @param {string} level - the level to set the logger to */ - setLogLevel = level => { + setLogLevel = (level) => { this.loggerInstance_.level = level } @@ -262,7 +262,18 @@ export class Reporter { * Logs a message at the info level. * @param {string} message - the message to log */ - info = message => { + debug = (message) => { + this.loggerInstance_.log({ + level: "debug", + message, + }) + } + + /** + * Logs a message at the info level. + * @param {string} message - the message to log + */ + info = (message) => { this.loggerInstance_.log({ level: "info", message, @@ -273,7 +284,7 @@ export class Reporter { * Logs a message at the warn level. * @param {string} message - the message to log */ - warn = message => { + warn = (message) => { this.loggerInstance_.warn({ level: "warn", message, diff --git a/packages/medusa-fulfillment-webshipper/package.json b/packages/medusa-fulfillment-webshipper/package.json index b66bfaa076..3a2aa20aae 100644 --- a/packages/medusa-fulfillment-webshipper/package.json +++ b/packages/medusa-fulfillment-webshipper/package.json @@ -18,6 +18,7 @@ "@babel/plugin-transform-runtime": "^7.7.6", "@babel/preset-env": "^7.7.5", "@babel/runtime": "^7.9.6", + "@medusajs/medusa": "^1.1.62", "client-sessions": "^0.8.0", "cross-env": "^5.2.1", "eslint": "^6.8.0", diff --git a/packages/medusa-fulfillment-webshipper/src/services/webshipper-fulfillment.js b/packages/medusa-fulfillment-webshipper/src/services/webshipper-fulfillment.js index 150a6dfe8b..bb90e57cc9 100644 --- a/packages/medusa-fulfillment-webshipper/src/services/webshipper-fulfillment.js +++ b/packages/medusa-fulfillment-webshipper/src/services/webshipper-fulfillment.js @@ -1,10 +1,15 @@ +import { TotalsService } from "@medusajs/medusa" +import { humanizeAmount } from "medusa-core-utils" import { FulfillmentService } from "medusa-interfaces" import Webshipper from "../utils/webshipper" class WebshipperFulfillmentService extends FulfillmentService { static identifier = "webshipper" - constructor({ logger, claimService, swapService, orderService }, options) { + constructor( + { logger, totalsService, claimService, swapService, orderService }, + options + ) { super() this.options_ = options @@ -25,6 +30,9 @@ class WebshipperFulfillmentService extends FulfillmentService { /** @private @const {OrderService} */ this.orderService_ = orderService + /** @private @const {TotalsService} */ + this.totalsService_ = totalsService + /** @private @const {SwapService} */ this.swapService_ = swapService @@ -170,22 +178,38 @@ class WebshipperFulfillmentService extends FulfillmentService { width: 15, length: 15, }, - customs_lines: returnOrder.items.map(({ item, quantity }) => { - return { - ext_ref: item.id, - sku: item.variant.sku, - description: item.title, - quantity: quantity, - country_of_origin: - item.variant.origin_country || - item.variant.product.origin_country, - tarif_number: - item.variant.hs_code || item.variant.product.hs_code, - unit_price: item.unit_price / 100, - vat_percent: fromOrder.tax_rate, - currency: fromOrder.currency_code.toUpperCase(), - } - }), + customs_lines: await Promise.all( + returnOrder.items.map(async ({ item, quantity }) => { + const totals = await this.totalsService_.getLineItemTotals( + item, + fromOrder, + { + include_tax: true, + use_tax_lines: true, + } + ) + return { + ext_ref: item.id, + sku: item.variant.sku, + description: item.title, + quantity: quantity, + country_of_origin: + item.variant.origin_country || + item.variant.product.origin_country, + tarif_number: + item.variant.hs_code || item.variant.product.hs_code, + unit_price: humanizeAmount( + totals.unit_price, + fromOrder.currency_code + ), + vat_percent: totals.tax_lines.reduce( + (acc, next) => acc + next.rate, + 0 + ), + currency: fromOrder.currency_code.toUpperCase(), + } + }) + ), }, ], sender_address: { @@ -329,21 +353,38 @@ class WebshipperFulfillmentService extends FulfillmentService { status: "pending", ext_ref, visible_ref, - order_lines: fulfillmentItems.map((item) => { - return { - ext_ref: item.id, - sku: item.variant.sku, - description: item.title, - quantity: item.quantity, - country_of_origin: - item.variant.origin_country || - item.variant.product.origin_country, - tarif_number: - item.variant.hs_code || item.variant.product.hs_code, - unit_price: item.unit_price / 100, - vat_percent: fromOrder.tax_rate, - } - }), + order_lines: await Promise.all( + fulfillmentItems.map(async (item) => { + const totals = await this.totalsService_.getLineItemTotals( + item, + fromOrder, + { + include_tax: true, + use_tax_lines: true, + } + ) + + return { + ext_ref: item.id, + sku: item.variant.sku, + description: item.title, + quantity: item.quantity, + country_of_origin: + item.variant.origin_country || + item.variant.product.origin_country, + tarif_number: + item.variant.hs_code || item.variant.product.hs_code, + unit_price: humanizeAmount( + totals.unit_price, + fromOrder.currency_code + ), + vat_percent: totals.tax_lines.reduce( + (acc, next) => acc + next.rate, + 0 + ), + } + }) + ), delivery_address: { att_contact: `${shipping_address.first_name} ${shipping_address.last_name}`, address_1: shipping_address.address_1, diff --git a/packages/medusa-js/src/resources/admin/index.ts b/packages/medusa-js/src/resources/admin/index.ts index 2b6e7079f0..8b1ed8ac0a 100644 --- a/packages/medusa-js/src/resources/admin/index.ts +++ b/packages/medusa-js/src/resources/admin/index.ts @@ -8,12 +8,14 @@ import AdminGiftCardsResource from "./gift-cards" import AdminInvitesResource from "./invites" import AdminNotesResource from "./notes" import AdminProductsResource from "./products" +import AdminProductTypesResource from "./product-types" import AdminUsersResource from "./users" import AdminReturnsResource from "./returns" import AdminOrdersResource from "./orders" import AdminReturnReasonsResource from "./return-reasons" import AdminVariantsResource from "./variants" import AdminSwapsResource from "./swaps" +import AdminTaxRatesResource from "./tax-rates" import AdminShippingProfilesResource from "./shipping-profiles" import AdminStoresResource from "./store" import AdminShippingOptionsResource from "./shipping-options" @@ -33,6 +35,7 @@ class Admin extends BaseResource { public notes = new AdminNotesResource(this.client) public products = new AdminProductsResource(this.client) public productTags = new AdminProductTagsResource(this.client) + public productTypes = new AdminProductTypesResource(this.client) public users = new AdminUsersResource(this.client) public returns = new AdminReturnsResource(this.client) public orders = new AdminOrdersResource(this.client) @@ -44,6 +47,7 @@ class Admin extends BaseResource { public shippingOptions = new AdminShippingOptionsResource(this.client) public regions = new AdminRegionsResource(this.client) public notifications = new AdminNotificationsResource(this.client) + public taxRates = new AdminTaxRatesResource(this.client) public uploads = new AdminUploadsResource(this.client) } diff --git a/packages/medusa-js/src/resources/admin/orders.ts b/packages/medusa-js/src/resources/admin/orders.ts index 660cf455ee..1d8258b959 100644 --- a/packages/medusa-js/src/resources/admin/orders.ts +++ b/packages/medusa-js/src/resources/admin/orders.ts @@ -22,7 +22,10 @@ import { ResponsePromise } from "../../typings" import BaseResource from "../base" class AdminOrdersResource extends BaseResource { - create(payload: AdminPostOrdersReq, customHeaders: Record = {}): ResponsePromise { + create( + payload: AdminPostOrdersReq, + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/orders` return this.client.request("POST", path, payload, {}, customHeaders) } @@ -30,17 +33,24 @@ class AdminOrdersResource extends BaseResource { update( id: string, payload: AdminPostOrdersOrderReq, - customHeaders: Record = {}): ResponsePromise { + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/orders/${id}` return this.client.request("POST", path, payload, {}, customHeaders) } - retrieve(id: string, customHeaders: Record = {}): ResponsePromise { + retrieve( + id: string, + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/orders/${id}` return this.client.request("GET", path, {}, {}, customHeaders) } - list(query?: AdminGetOrdersParams, customHeaders: Record = {}): ResponsePromise { + list( + query?: AdminGetOrdersParams, + customHeaders: Record = {} + ): ResponsePromise { let path = `/admin/orders` if (query) { @@ -51,12 +61,18 @@ class AdminOrdersResource extends BaseResource { return this.client.request("GET", path, {}, {}, customHeaders) } - complete(id: string, customHeaders: Record = {}): ResponsePromise { + complete( + id: string, + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/orders/${id}/complete` return this.client.request("POST", path, {}, {}, customHeaders) } - capturePayment(id: string, customHeaders: Record = {}): ResponsePromise { + capturePayment( + id: string, + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/orders/${id}/capture` return this.client.request("POST", path, {}, {}, customHeaders) } @@ -64,7 +80,8 @@ class AdminOrdersResource extends BaseResource { refundPayment( id: string, payload: AdminPostOrdersOrderRefundsReq, - customHeaders: Record = {}): ResponsePromise { + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/orders/${id}/refund` return this.client.request("POST", path, payload, {}, customHeaders) } @@ -72,7 +89,8 @@ class AdminOrdersResource extends BaseResource { createFulfillment( id: string, payload: AdminPostOrdersOrderFulfillmentsReq, - customHeaders: Record = {}): ResponsePromise { + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/orders/${id}/fulfillment` return this.client.request("POST", path, payload, {}, customHeaders) } @@ -124,7 +142,10 @@ class AdminOrdersResource extends BaseResource { return this.client.request("POST", path, payload, {}, customHeaders) } - cancel(id: string, customHeaders: Record = {}): ResponsePromise { + cancel( + id: string, + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/orders/${id}/cancel` return this.client.request("POST", path, {}, {}, customHeaders) } @@ -138,7 +159,10 @@ class AdminOrdersResource extends BaseResource { return this.client.request("POST", path, payload, {}, customHeaders) } - archive(id: string, customHeaders: Record = {}): ResponsePromise { + archive( + id: string, + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/orders/${id}/archive` return this.client.request("POST", path, {}, {}, customHeaders) } @@ -152,7 +176,11 @@ class AdminOrdersResource extends BaseResource { return this.client.request("POST", path, payload, {}, customHeaders) } - cancelSwap(id: string, swapId: string, customHeaders: Record = {}): ResponsePromise { + cancelSwap( + id: string, + swapId: string, + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/orders/${id}/swaps/${swapId}/cancel` return this.client.request("POST", path, {}, {}, customHeaders) } @@ -195,7 +223,11 @@ class AdminOrdersResource extends BaseResource { return this.client.request("POST", path, payload, {}, customHeaders) } - cancelClaim(id: string, claimId: string, customHeaders: Record = {}): ResponsePromise { + cancelClaim( + id: string, + claimId: string, + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/orders/${id}/claims/${claimId}/cancel` return this.client.request("POST", path, {}, {}, customHeaders) } @@ -230,7 +262,11 @@ class AdminOrdersResource extends BaseResource { return this.client.request("POST", path, payload, {}, customHeaders) } - deleteMetadata(id: string, key: string, customHeaders: Record = {}): ResponsePromise { + deleteMetadata( + id: string, + key: string, + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/orders/${id}/metadata/${key}` return this.client.request("DELETE", path, {}, {}, customHeaders) } diff --git a/packages/medusa-js/src/resources/admin/product-types.ts b/packages/medusa-js/src/resources/admin/product-types.ts new file mode 100644 index 0000000000..13f048614f --- /dev/null +++ b/packages/medusa-js/src/resources/admin/product-types.ts @@ -0,0 +1,24 @@ +import { + AdminGetProductTypesParams, + AdminProductTypesListRes, +} from "@medusajs/medusa" +import qs from "qs" +import { ResponsePromise } from "../../typings" +import BaseResource from "../base" + +class AdminProductTypesResource extends BaseResource { + list( + query?: AdminGetProductTypesParams + ): ResponsePromise { + let path = `/admin/product-types` + + if (query) { + const queryString = qs.stringify(query) + path = `/admin/product-types?${queryString}` + } + + return this.client.request("GET", path) + } +} + +export default AdminProductTypesResource diff --git a/packages/medusa-js/src/resources/admin/products.ts b/packages/medusa-js/src/resources/admin/products.ts index 9f767284ab..e18b5bad2a 100644 --- a/packages/medusa-js/src/resources/admin/products.ts +++ b/packages/medusa-js/src/resources/admin/products.ts @@ -20,12 +20,18 @@ import { ResponsePromise } from "../../typings" import BaseResource from "../base" class AdminProductsResource extends BaseResource { - create(payload: AdminPostProductsReq, customHeaders: Record = {}): ResponsePromise { + create( + payload: AdminPostProductsReq, + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/products/` return this.client.request("POST", path, payload, {}, customHeaders) } - retrieve(id: string, customHeaders: Record = {}): ResponsePromise { + retrieve( + id: string, + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/products/${id}` return this.client.request("GET", path, {}, {}, customHeaders) } @@ -33,17 +39,24 @@ class AdminProductsResource extends BaseResource { update( id: string, payload: AdminPostProductsProductReq, - customHeaders: Record = {}): ResponsePromise { + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/products/${id}` return this.client.request("POST", path, payload, {}, customHeaders) } - delete(id: string, customHeaders: Record = {}): ResponsePromise { + delete( + id: string, + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/products/${id}` return this.client.request("DELETE", path, {}, {}, customHeaders) } - list(query?: AdminGetProductsParams, customHeaders: Record = {}): ResponsePromise { + list( + query?: AdminGetProductsParams, + customHeaders: Record = {} + ): ResponsePromise { let path = `/admin/products` if (query) { @@ -54,12 +67,16 @@ class AdminProductsResource extends BaseResource { return this.client.request("GET", path, {}, {}, customHeaders) } - listTypes(customHeaders: Record = {}): ResponsePromise { + listTypes( + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/products/types` return this.client.request("GET", path, {}, {}, customHeaders) } - listTags(customHeaders: Record = {}): ResponsePromise { + listTags( + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/products/tag-usage` return this.client.request("GET", path, {}, {}, customHeaders) } diff --git a/packages/medusa-js/src/resources/admin/store.ts b/packages/medusa-js/src/resources/admin/store.ts index b5f37cb52e..6769335920 100644 --- a/packages/medusa-js/src/resources/admin/store.ts +++ b/packages/medusa-js/src/resources/admin/store.ts @@ -1,5 +1,6 @@ import { AdminPaymentProvidersList, + AdminTaxProvidersList, AdminPostStoreReq, AdminStoresRes, } from "@medusajs/medusa" @@ -13,7 +14,10 @@ class AdminStoresResource extends BaseResource { * @param customHeaders * @returns the updated store. */ - update(payload: AdminPostStoreReq, customHeaders: Record = {}): ResponsePromise { + update( + payload: AdminPostStoreReq, + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/store/` return this.client.request("POST", path, payload, {}, customHeaders) } @@ -24,7 +28,10 @@ class AdminStoresResource extends BaseResource { * @param customHeaders * @returns updated store. */ - addCurrency(currency_code: string, customHeaders: Record = {}): ResponsePromise { + addCurrency( + currency_code: string, + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/store/${currency_code}` return this.client.request("POST", path, {}, {}, customHeaders) } @@ -35,7 +42,10 @@ class AdminStoresResource extends BaseResource { * @param customHeaders * @returns updated store */ - deleteCurrency(currency_code: string, customHeaders: Record = {}): ResponsePromise { + deleteCurrency( + currency_code: string, + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/store/currencies/${currency_code}` return this.client.request("DELETE", path, {}, {}, customHeaders) } @@ -44,7 +54,9 @@ class AdminStoresResource extends BaseResource { * @description gets a medusa store * @returns a medusa store */ - retrieve(customHeaders: Record = {}): ResponsePromise { + retrieve( + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/store/` return this.client.request("GET", path, {}, {}, customHeaders) } @@ -53,10 +65,23 @@ class AdminStoresResource extends BaseResource { * @description Lists the store's payment providers * @returns a list of payment providers configured on the store */ - listPaymentProviders(customHeaders: Record = {}): ResponsePromise { + listPaymentProviders( + customHeaders: Record = {} + ): ResponsePromise { const path = `/admin/store/payment-providers` return this.client.request("GET", path, {}, {}, customHeaders) } + + /** + * @description Lists the store's payment providers + * @returns a list of payment providers configured on the store + */ + listTaxProviders( + customHeaders: Record = {} + ): ResponsePromise { + const path = `/admin/store/tax-providers` + return this.client.request("GET", path, {}, {}, customHeaders) + } } export default AdminStoresResource diff --git a/packages/medusa-js/src/resources/admin/tax-rates.ts b/packages/medusa-js/src/resources/admin/tax-rates.ts new file mode 100644 index 0000000000..ba4c672c63 --- /dev/null +++ b/packages/medusa-js/src/resources/admin/tax-rates.ts @@ -0,0 +1,189 @@ +import { + AdminTaxRatesRes, + AdminTaxRatesListRes, + AdminTaxRatesDeleteRes, + AdminGetTaxRatesParams, + AdminGetTaxRatesTaxRateParams, + AdminDeleteTaxRatesTaxRateProductsReq, + AdminDeleteTaxRatesTaxRateProductsParams, + AdminDeleteTaxRatesTaxRateProductTypesReq, + AdminDeleteTaxRatesTaxRateProductTypesParams, + AdminDeleteTaxRatesTaxRateShippingOptionsReq, + AdminDeleteTaxRatesTaxRateShippingOptionsParams, + AdminPostTaxRatesReq, + AdminPostTaxRatesTaxRateReq, + AdminPostTaxRatesTaxRateProductsReq, + AdminPostTaxRatesTaxRateProductTypesReq, + AdminPostTaxRatesTaxRateShippingOptionsReq, +} from "@medusajs/medusa" +import qs from "qs" +import { ResponsePromise } from "../../typings" +import BaseResource from "../base" + +class AdminTaxRatesResource extends BaseResource { + retrieve( + id: string, + query?: AdminGetTaxRatesTaxRateParams, + customHeaders: Record = {} + ): ResponsePromise { + let path = `/admin/tax-rates/${id}` + + if (query) { + const queryString = qs.stringify(query) + path = `/admin/tax-rates/${id}?${queryString}` + } + + return this.client.request("GET", path, {}, {}, customHeaders) + } + + list( + query?: AdminGetTaxRatesParams, + customHeaders: Record = {} + ): ResponsePromise { + let path = `/admin/tax-rates` + + if (query) { + const queryString = qs.stringify(query) + path = `/admin/tax-rates?${queryString}` + } + + return this.client.request("GET", path, {}, {}, customHeaders) + } + + create( + payload: AdminPostTaxRatesReq, + query?: AdminGetTaxRatesTaxRateParams, + customHeaders: Record = {} + ): ResponsePromise { + let path = `/admin/tax-rates` + + if (query) { + const queryString = qs.stringify(query) + path = `/admin/tax-rates?${queryString}` + } + + return this.client.request("POST", path, payload, {}, customHeaders) + } + + update( + id: string, + payload: AdminPostTaxRatesTaxRateReq, + query?: AdminGetTaxRatesTaxRateParams, + customHeaders: Record = {} + ): ResponsePromise { + let path = `/admin/tax-rates/${id}` + + if (query) { + const queryString = qs.stringify(query) + path = `/admin/tax-rates/${id}?${queryString}` + } + + return this.client.request("POST", path, payload, {}, customHeaders) + } + + addProducts( + id: string, + payload: AdminPostTaxRatesTaxRateProductsReq, + query?: AdminGetTaxRatesTaxRateParams, + customHeaders: Record = {} + ): ResponsePromise { + let path = `/admin/tax-rates/${id}/products/batch` + + if (query) { + const queryString = qs.stringify(query) + path = `/admin/tax-rates/${id}/products/batch?${queryString}` + } + + return this.client.request("POST", path, payload, {}, customHeaders) + } + + addProductTypes( + id: string, + payload: AdminPostTaxRatesTaxRateProductTypesReq, + query?: AdminGetTaxRatesTaxRateParams, + customHeaders: Record = {} + ): ResponsePromise { + let path = `/admin/tax-rates/${id}/product-types/batch` + + if (query) { + const queryString = qs.stringify(query) + path = `/admin/tax-rates/${id}/product-types/batch?${queryString}` + } + + return this.client.request("POST", path, payload, {}, customHeaders) + } + + addShippingOptions( + id: string, + payload: AdminPostTaxRatesTaxRateShippingOptionsReq, + query?: AdminGetTaxRatesTaxRateParams, + customHeaders: Record = {} + ): ResponsePromise { + let path = `/admin/tax-rates/${id}/shipping-options/batch` + + if (query) { + const queryString = qs.stringify(query) + path = `/admin/tax-rates/${id}/shipping-options/batch?${queryString}` + } + + return this.client.request("POST", path, payload, {}, customHeaders) + } + + removeProducts( + id: string, + payload: AdminDeleteTaxRatesTaxRateProductsReq, + query?: AdminDeleteTaxRatesTaxRateProductsParams, + customHeaders: Record = {} + ): ResponsePromise { + let path = `/admin/tax-rates/${id}/products/batch` + + if (query) { + const queryString = qs.stringify(query) + path = `/admin/tax-rates/${id}/products/batch?${queryString}` + } + + return this.client.request("DELETE", path, payload, {}, customHeaders) + } + + removeProductTypes( + id: string, + payload: AdminDeleteTaxRatesTaxRateProductTypesReq, + query?: AdminDeleteTaxRatesTaxRateProductTypesParams, + customHeaders: Record = {} + ): ResponsePromise { + let path = `/admin/tax-rates/${id}/product-types/batch` + + if (query) { + const queryString = qs.stringify(query) + path = `/admin/tax-rates/${id}/product-types/batch?${queryString}` + } + + return this.client.request("DELETE", path, payload, {}, customHeaders) + } + + removeShippingOptions( + id: string, + payload: AdminDeleteTaxRatesTaxRateShippingOptionsReq, + query?: AdminDeleteTaxRatesTaxRateShippingOptionsParams, + customHeaders: Record = {} + ): ResponsePromise { + let path = `/admin/tax-rates/${id}/shipping-options/batch` + + if (query) { + const queryString = qs.stringify(query) + path = `/admin/tax-rates/${id}/shipping-options/batch?${queryString}` + } + + return this.client.request("DELETE", path, payload, {}, customHeaders) + } + + delete( + id: string, + customHeaders: Record = {} + ): ResponsePromise { + const path = `/admin/tax-rates/${id}` + return this.client.request("DELETE", path, {}, {}, customHeaders) + } +} + +export default AdminTaxRatesResource diff --git a/packages/medusa-payment-klarna/src/__mocks__/totals.js b/packages/medusa-payment-klarna/src/__mocks__/totals.js index 9f1c9234b8..5c1fd3f03b 100644 --- a/packages/medusa-payment-klarna/src/__mocks__/totals.js +++ b/packages/medusa-payment-klarna/src/__mocks__/totals.js @@ -3,6 +3,18 @@ export const TotalsServiceMock = { getTaxTotal: jest.fn(), getAllocationItemDiscounts: jest.fn(), getDiscountTotal: jest.fn(), + getLineItemTotals: jest.fn(() => { + return { + total: 10, + tax_lines: [], + } + }), + getShippingMethodTotals: jest.fn(() => { + return { + total: 10, + tax_lines: [], + } + }), } const mock = jest.fn().mockImplementation(() => { diff --git a/packages/medusa-payment-klarna/src/services/klarna-provider.js b/packages/medusa-payment-klarna/src/services/klarna-provider.js index dd5fe45210..03ce9ecf32 100644 --- a/packages/medusa-payment-klarna/src/services/klarna-provider.js +++ b/packages/medusa-payment-klarna/src/services/klarna-provider.js @@ -5,7 +5,7 @@ import { PaymentService } from "medusa-interfaces" class KlarnaProviderService extends PaymentService { static identifier = "klarna" - constructor({ shippingProfileService }, options) { + constructor({ shippingProfileService, totalsService }, options) { super() /** @@ -41,48 +41,66 @@ class KlarnaProviderService extends PaymentService { /** @private @const {ShippingProfileService} */ this.shippingProfileService_ = shippingProfileService + + /** @private @const {TotalsService} */ + this.totalsService_ = totalsService } - async lineItemsToOrderLines_(cart, taxRate) { + async lineItemsToOrderLines_(cart) { let order_lines = [] - const tax = taxRate / 100 - - cart.items.forEach((item) => { + for (const item of cart.items) { // Withdraw discount from the total item amount const quantity = item.quantity - const unit_price = item.unit_price * (tax + 1) - const total_amount = unit_price * quantity - const total_tax_amount = total_amount * (tax / (1 + tax)) + + const totals = await this.totalsService_.getLineItemTotals(item, cart, { + include_tax: true, + }) + + const tax = + totals.tax_lines.reduce((acc, next) => acc + next.rate, 0) / 100 order_lines.push({ name: item.title, tax_rate: tax * 10000, quantity, - unit_price, - total_amount, - total_tax_amount, + unit_price: Math.round(totals.original_total / item.quantity), + total_amount: totals.total - totals.gift_card_total, + total_tax_amount: totals.tax_total, + total_discount_amount: + totals.original_total - totals.total + totals.gift_card_total, }) - }) + } if (cart.shipping_methods.length) { - const { name, price } = cart.shipping_methods.reduce( - (acc, next) => { - acc.name = [...acc.name, next?.shipping_option.name] - acc.price += next.price - return acc - }, - { name: [], price: 0 } - ) + const name = [] + let total = 0 + let tax = 0 + + for (const next of cart.shipping_methods) { + const totals = await this.totalsService_.getShippingMethodTotals( + next, + cart, + { + include_tax: true, + } + ) + + name.push(next?.shipping_option.name) + total += totals.total + tax += totals.tax_total + } + + const taxRate = tax / (total - tax) order_lines.push({ name: name?.join(" + ") || "Shipping fee", quantity: 1, type: "shipping_fee", - unit_price: price * (1 + tax), - tax_rate: tax * 10000, - total_amount: price * (1 + tax), - total_tax_amount: price * tax, + unit_price: total, + tax_rate: taxRate * 10000, + total_amount: total, + total_tax_amount: tax, }) } @@ -96,45 +114,20 @@ class KlarnaProviderService extends PaymentService { locale: "en-US", } - const { region, gift_card_total, discount_total, tax_total, total } = cart + const { region, gift_card_total, tax_total, total } = cart - const taxRate = region.tax_rate / 100 + order.order_lines = await this.lineItemsToOrderLines_(cart) - order.order_lines = await this.lineItemsToOrderLines_(cart, region.tax_rate) - - if (discount_total > 0) { - order.order_lines.push({ - name: `Discount`, - quantity: 1, - type: "discount", - unit_price: 0, - total_discount_amount: discount_total * (1 + taxRate), - tax_rate: taxRate * 10000, - total_amount: -discount_total * (1 + taxRate), - total_tax_amount: -discount_total * taxRate, - }) - } else if (discount_total < 0) { - order.order_lines.push({ - name: `Discount Payback`, - quantity: 1, - type: "surcharge", - unit_price: -discount_total * (1 + taxRate), - tax_rate: taxRate * 10000, - total_amount: -discount_total * (1 + taxRate), - total_tax_amount: -discount_total * taxRate, - }) - } - - if (gift_card_total) { + if (gift_card_total && !region.gift_cards_taxable) { order.order_lines.push({ name: `Gift Card`, quantity: 1, type: "gift_card", unit_price: 0, - total_discount_amount: gift_card_total * (1 + taxRate), - tax_rate: taxRate * 10000, - total_amount: -gift_card_total * (1 + taxRate), - total_tax_amount: -gift_card_total * taxRate, + total_discount_amount: gift_card_total, + tax_rate: 0, + total_amount: -gift_card_total, + total_tax_amount: 0, }) } @@ -185,11 +178,20 @@ class KlarnaProviderService extends PaymentService { // shipping_options and set the selected shipping method if (cart.shipping_methods.length) { const shipping_method = cart.shipping_methods[0] + const totals = await this.totalsService_.getShippingMethodTotals( + shipping_method, + cart, + { + include_tax: true, + } + ) + + const taxRate = totals.tax_total / (totals.total - totals.tax_total) order.selected_shipping_option = { id: shipping_method.shipping_option.id, name: shipping_method.shipping_option.name, - price: shipping_method.price * (1 + taxRate), - tax_amount: shipping_method.price * taxRate, + price: totals.total, + tax_amount: total.tax_total, tax_rate: taxRate * 10000, } } @@ -213,6 +215,8 @@ class KlarnaProviderService extends PaymentService { const methods = Object.keys(partitioned).map((k) => partitioned[k]) const combinations = cartesian(...methods) + const taxRate = region.tax_rate / 100 + // Use the cartesian product of shipping methods to generate correct // format for the Klarna Widget order.shipping_options = combinations.map((combination) => { diff --git a/packages/medusa-plugin-brightpearl/src/services/__tests__/brightpearl.js b/packages/medusa-plugin-brightpearl/src/services/__tests__/brightpearl.js index dcb359ab2e..41aec8fae2 100644 --- a/packages/medusa-plugin-brightpearl/src/services/__tests__/brightpearl.js +++ b/packages/medusa-plugin-brightpearl/src/services/__tests__/brightpearl.js @@ -156,6 +156,20 @@ const TotalsService = { getTotal: () => { return Promise.resolve(123) }, + getShippingMethodTotals: () => { + return { + price: 0, + discount_total: 0, + tax_total: 0, + } + }, + getLineItemTotals: () => { + return { + subtotal: 15800, + discount_total: 0, + tax_total: 3950, + } + }, getLineDiscounts: (o) => { if (o.id === "rounding") { return [ @@ -242,76 +256,6 @@ describe("BrightpearlService", () => { }) }) - describe("createSalesOrder", () => { - const bpService = new BrightpearlService( - { - orderService: OrderService, - totalsService: TotalsService, - oauthService: OAuthService, - regionService: RegionService, - }, - { account: "test" } - ) - - it("successfully builds sales order", async () => { - jest.clearAllMocks() - - await bpService.createSalesOrder(order) - - expect(mockCreateOrder).toHaveBeenCalledWith({ - currency: { code: "DKK" }, - ref: "1234", - externalRef: "12355", - channelId: "1", - installedIntegrationInstanceId: undefined, - statusId: "3", - customer: { - id: "12345", - address: { - addressFullName: "Test Testson", - addressLine1: "Test", - addressLine2: "TEst", - postalCode: "1234", - countryIsoCode: "DK", - telephone: "12345678", - email: "test@example.com", - }, - }, - delivery: { - shippingMethodId: 0, - address: { - addressFullName: "Test Testson", - addressLine1: "Test", - addressLine2: "TEst", - postalCode: "1234", - countryIsoCode: "DK", - telephone: "12345678", - email: "test@example.com", - }, - }, - rows: [ - { - name: "Test", - net: 22, - tax: 5.082, - quantity: 2, - taxCode: "1234", - externalRef: undefined, - nominalCode: "4000", - }, - { - name: "Shipping: standard", - quantity: 1, - net: 123.99, - tax: 28.6417, - taxCode: "1234", - nominalCode: "4040", - }, - ], - }) - }) - }) - describe("rounding", () => { const bpService = new BrightpearlService( { diff --git a/packages/medusa-plugin-brightpearl/src/services/brightpearl.js b/packages/medusa-plugin-brightpearl/src/services/brightpearl.js index bd1ca66af2..d62946d23f 100644 --- a/packages/medusa-plugin-brightpearl/src/services/brightpearl.js +++ b/packages/medusa-plugin-brightpearl/src/services/brightpearl.js @@ -322,15 +322,8 @@ class BrightpearlService extends BaseService { name: `${fromRefund.reason}: ${fromRefund.note}`, quantity: 1, taxCode: region.tax_code, - net: this.bpnum_( - fromRefund.amount, - fromOrder.currency_code, - 10000 / (100 + fromOrder.tax_rate) - ), - tax: this.bpnum_( - fromRefund.amount * (1 - 100 / (100 + fromOrder.tax_rate)), - fromOrder.currency_code - ), + net: this.bpnum_(fromRefund.amount, fromOrder.currency_code), + tax: 0, nominalCode: accountingCode, }, ], @@ -410,6 +403,29 @@ class BrightpearlService extends BaseService { }), } + if (fromReturn.shipping_method) { + const totals = await this.totalsService_.getShippingMethodTotals( + fromReturn.shipping_method, + fromOrder, + { + include_tax: true, + use_tax_lines: true, + } + ) + + order.rows.push({ + net: this.bpnum_( + -1 * (totals.total - totals.tax_total), + fromOrder.currency_code + ), + tax: this.bpnum_(-1 * totals.tax_total, fromOrder.currency_code), + name: "Return shipping", + taxCode: region.tax_code, + nominalCode: this.options.shipping_account_code || "4040", + quantity: 1, + }) + } + const total = order.rows.reduce((acc, next) => { return acc + next.net + next.tax }, 0) @@ -421,15 +437,8 @@ class BrightpearlService extends BaseService { name: "Difference", quantity: 1, taxCode: region.tax_code, - net: this.bpnum_( - difference, - fromOrder.currency_code, - 10000 / (100 + fromOrder.tax_rate) - ), - tax: this.bpnum_( - difference * (1 - 100 / (100 + fromOrder.tax_rate)), - fromOrder.currency_code - ), + net: this.bpround_(difference), + tax: 0, nominalCode: this.options.sales_account_code || "4000", }) } @@ -811,14 +820,24 @@ class BrightpearlService extends BaseService { fromSwap.return_order.shipping_method && fromSwap.return_order.shipping_method.price ) { + const shippingTotals = + await this.totalsService_.getShippingMethodTotals( + fromSwap.return_order.shipping_method, + fromOrder, + { + include_tax: true, + use_tax_lines: true, + } + ) order.rows.push({ name: "Return Shipping", quantity: 1, taxCode: region.tax_code, - net: (-1 * fromSwap.return_order.shipping_method.price) / 100, - tax: - ((-1 * fromSwap.return_order.shipping_method.price) / 100) * - (fromOrder.tax_rate / 100), + net: this.bpnum_(1 * shippingTotals.price, fromOrder.currency_code), + tax: this.bpnum_( + 1 * shippingTotals.tax_total, + fromOrder.currency_code + ), nominalCode: this.options.shipping_account_code || "4040", }) } @@ -882,21 +901,19 @@ class BrightpearlService extends BaseService { config = { include_price: true, is_claim: false } ) { const { region } = fromOrder - const discount = fromOrder.discounts.find( - ({ rule }) => rule.type !== "free_shipping" - ) - let lineDiscounts = [] - if (discount) { - lineDiscounts = this.totalsService_.getLineDiscounts(fromOrder, discount) - } const lines = await Promise.all( fromOrder.items.map(async (item) => { const bpProduct = await this.retrieveProductBySKU(item.variant.sku) - const ld = lineDiscounts.find((l) => item.id === l.item.id) || { - amount: 0, - } + const lineTotals = await this.totalsService_.getLineItemTotals( + item, + fromOrder, + { + include_tax: true, + use_tax_lines: true, + } + ) const row = {} if (bpProduct) { @@ -907,23 +924,20 @@ class BrightpearlService extends BaseService { if (config.include_price) { row.net = this.bpnum_( - item.unit_price * item.quantity - ld.amount, + lineTotals.subtotal - lineTotals.discount_total, fromOrder.currency_code ) - row.tax = this.bpnum_( - item.unit_price * item.quantity - ld.amount, - fromOrder.currency_code, - fromOrder.tax_rate - ) + row.tax = this.bpnum_(lineTotals.tax_total, fromOrder.currency_code) } else if (config.is_claim) { row.net = await this.retrieveProductPrice( bpProduct.productId, this.options.cost_price_list || `1` ) + row.tax = this.bpnum_( row.net * 100, fromOrder.currency_code, - fromOrder.tax_rate + lineTotals.tax_lines.reduce((acc, next) => acc + next.rate, 0) ) } @@ -948,34 +962,48 @@ class BrightpearlService extends BaseService { // purchased. const gcTotal = fromOrder.gift_card_total if (gcTotal) { + let tax = 0 + if (fromOrder.region.gift_cards_taxable) { + tax = this.bpnum_( + -1 * gcTotal, + fromOrder.currency_code, + fromOrder.region.tax_rate + ) + } + lines.push({ name: `Gift Card`, net: this.bpnum_(-1 * gcTotal, fromOrder.currency_code), - tax: this.bpnum_( - -1 * gcTotal, - fromOrder.currency_code, - fromOrder.tax_rate - ), + tax, quantity: 1, taxCode: region.tax_code, nominalCode: this.options.gift_card_account_code || "4000", }) } - const shippingTotal = - fromOrder.shipping_total || - this.totalsService_.getShippingTotal(fromOrder) const shippingMethods = fromOrder.shipping_methods if (shippingMethods.length > 0) { + const shippingTotal = await shippingMethods.reduce(async (acc, next) => { + const accum = await acc + const totals = await this.totalsService_.getShippingMethodTotals( + next, + fromOrder, + { + include_tax: true, + use_tax_lines: true, + } + ) + return { + price: accum.price + totals.price, + tax: accum.tax + totals.tax_total, + } + }, Promise.resolve({ price: 0, tax: 0 })) + lines.push({ name: `Shipping: ${shippingMethods.map((m) => m.name).join(" + ")}`, quantity: 1, - net: this.bpnum_(shippingTotal, fromOrder.currency_code), - tax: this.bpnum_( - shippingTotal, - fromOrder.currency_code, - fromOrder.tax_rate - ), + net: this.bpnum_(shippingTotal.price, fromOrder.currency_code), + tax: this.bpnum_(shippingTotal.tax, fromOrder.currency_code), taxCode: region.tax_code, nominalCode: this.options.shipping_account_code || "4040", }) diff --git a/packages/medusa-plugin-brightpearl/src/subscribers/order.js b/packages/medusa-plugin-brightpearl/src/subscribers/order.js index 6af07f9ac3..547a487e6d 100644 --- a/packages/medusa-plugin-brightpearl/src/subscribers/order.js +++ b/packages/medusa-plugin-brightpearl/src/subscribers/order.js @@ -72,21 +72,20 @@ class OrderSubscriber { const fromSwap = await this.swapService_.retrieve(id, { relations: [ - "order", - "order.payments", - "order.region", - "order.swaps", - "order.discounts", - "order.discounts.rule", "return_order", "return_order.items", "return_order.shipping_method", + "return_order.shipping_method.tax_lines", "additional_items", + "additional_items.tax_lines", "shipping_address", "shipping_methods", + "shipping_methods.tax_lines", ], }) - let fromOrder = fromSwap.order + const fromOrder = await this.orderService_.retrieve(fromSwap.order_id, { + relations: ["payments", "region", "swaps", "discounts", "discounts.rule"], + }) if ( !( @@ -105,23 +104,27 @@ class OrderSubscriber { const { id } = data const fromClaim = await this.claimService_.retrieve(id, { relations: [ - "order", - "order.payments", - "order.region", - "order.claims", - "order.discounts", - "order.discounts.rule", "claim_items", "return_order", "return_order.items", "return_order.shipping_method", + "return_order.shipping_method.tax_lines", "additional_items", + "additional_items.tax_lines", "shipping_address", "shipping_methods", ], }) - const fromOrder = fromClaim.order + const fromOrder = await this.orderService_.retrieve(fromClaim.order_id, { + relations: [ + "payments", + "region", + "claims", + "discounts", + "discounts.rule", + ], + }) if (fromClaim.type === "replace") { await this.brightpearlService_.createClaim(fromOrder, fromClaim) @@ -147,11 +150,11 @@ class OrderSubscriber { const { id, return_id } = data const order = await this.orderService_.retrieve(id, { - relations: ["region", "swaps", "payments"], + relations: ["discounts", "region", "swaps", "payments"], }) const fromReturn = await this.returnService_.retrieve(return_id, { - relations: ["items"], + relations: ["items", "shipping_method", "shipping_method.tax_lines"], }) return this.brightpearlService_ diff --git a/packages/medusa-plugin-segment/src/services/__tests__/segment.js b/packages/medusa-plugin-segment/src/services/__tests__/segment.js index dff49cc3d0..0aba781155 100644 --- a/packages/medusa-plugin-segment/src/services/__tests__/segment.js +++ b/packages/medusa-plugin-segment/src/services/__tests__/segment.js @@ -64,8 +64,11 @@ describe("SegmentService", () => { } const TotalsService = { - getLineItemRefund: (_, item) => { - return item.unit_price + getLineItemTotals: (item) => { + return { + total: item.unit_price, + tax_total: 0, + } }, } @@ -101,10 +104,10 @@ describe("SegmentService", () => { { category: "Collection", name: "Test", - price: 4.47, + price: 5.5, product_id: "prod_123", quantity: 2, - reporting_revenue: 8.94, + reporting_revenue: 11, sku: "", subtitle: "Subtitle", type: "Type", @@ -160,10 +163,10 @@ describe("SegmentService", () => { { category: "Collection", name: "Test", - price: 4.47, + price: 5.5, product_id: "prod_123", quantity: 2, - reporting_revenue: 8.94, + reporting_revenue: 11, sku: "", subtitle: "Subtitle", type: "Type", @@ -214,10 +217,10 @@ describe("SegmentService", () => { { category: "Collection", name: "Test", - price: 446.79, + price: 550, product_id: "prod_123", quantity: 2, - reporting_revenue: 893.58, + reporting_revenue: 1100, sku: "", subtitle: "Subtitle", type: "Type", diff --git a/packages/medusa-plugin-segment/src/services/segment.js b/packages/medusa-plugin-segment/src/services/segment.js index 89c56c3a57..caaae460e4 100644 --- a/packages/medusa-plugin-segment/src/services/segment.js +++ b/packages/medusa-plugin-segment/src/services/segment.js @@ -73,8 +73,6 @@ class SegmentService extends BaseService { coupon = order.discounts[0] && order.discounts[0].code } - const taxRate = order.tax_rate / 100 - const orderData = { checkout_id: order.cart_id, order_id: order.id, @@ -113,15 +111,18 @@ class SegmentService extends BaseService { products: await Promise.all( order.items.map(async (item) => { let name = item.title - const lineTotalTax = this.totalsService_.getLineItemRefund( + const totals = await this.totalsService_.getLineItemTotals( + item, order, - item + { + include_tax: true, + } ) - const lineTotal = lineTotalTax / (1 + taxRate) + const lineTotal = totals.total - totals.tax_total const revenue = await this.getReportingValue( - order.currency_code, + curr, humanizeAmount(lineTotal, curr) ) diff --git a/packages/medusa-plugin-sendgrid/src/services/sendgrid.js b/packages/medusa-plugin-sendgrid/src/services/sendgrid.js index d951685bd9..3cf920ed8c 100644 --- a/packages/medusa-plugin-sendgrid/src/services/sendgrid.js +++ b/packages/medusa-plugin-sendgrid/src/services/sendgrid.js @@ -349,7 +349,7 @@ class SendGridService extends NotificationService { } } - async orderPlacedData({ id }) { + async orderCanceledData({ id }) { const order = await this.orderService_.retrieve(id, { select: [ "shipping_total", @@ -448,6 +448,131 @@ class SendGridService extends NotificationService { } } + async orderPlacedData({ id }) { + const order = await this.orderService_.retrieve(id, { + select: [ + "shipping_total", + "discount_total", + "tax_total", + "refunded_total", + "gift_card_total", + "subtotal", + "total", + ], + relations: [ + "customer", + "billing_address", + "shipping_address", + "discounts", + "discounts.rule", + "discounts.rule.valid_for", + "shipping_methods", + "shipping_methods.shipping_option", + "payments", + "fulfillments", + "returns", + "gift_cards", + "gift_card_transactions", + ], + }) + + const { tax_total, shipping_total, gift_card_total, total } = order + + const currencyCode = order.currency_code.toUpperCase() + + const items = await Promise.all( + order.items.map(async (i) => { + i.totals = await this.totalsService_.getLineItemTotals(i, order, { + include_tax: true, + use_tax_lines: true, + }) + i.thumbnail = this.normalizeThumbUrl_(i.thumbnail) + i.discounted_price = `${this.humanPrice_( + i.totals.total / i.quantity, + currencyCode + )} ${currencyCode}` + i.price = `${this.humanPrice_( + i.totals.original_total / i.quantity, + currencyCode + )} ${currencyCode}` + return i + }) + ) + + let discounts = [] + if (order.discounts) { + discounts = order.discounts.map((discount) => { + return { + is_giftcard: false, + code: discount.code, + descriptor: `${discount.rule.value}${ + discount.rule.type === "percentage" ? "%" : ` ${currencyCode}` + }`, + } + }) + } + + let giftCards = [] + if (order.gift_cards) { + giftCards = order.gift_cards.map((gc) => { + return { + is_giftcard: true, + code: gc.code, + descriptor: `${gc.value} ${currencyCode}`, + } + }) + + discounts.concat(giftCards) + } + + const locale = await this.extractLocale(order) + + // Includes taxes in discount amount + const discountTotal = items.reduce((acc, i) => { + return acc + i.totals.original_total - i.totals.total + }, 0) + + const discounted_subtotal = items.reduce((acc, i) => { + return acc + i.totals.total + }, 0) + const subtotal = items.reduce((acc, i) => { + return acc + i.totals.original_total + }, 0) + + const subtotal_ex_tax = items.reduce((total, i) => { + return total + i.totals.subtotal + }, 0) + + return { + ...order, + locale, + has_discounts: order.discounts.length, + has_gift_cards: order.gift_cards.length, + date: order.created_at.toDateString(), + items, + discounts, + subtotal_ex_tax: `${this.humanPrice_( + subtotal_ex_tax, + currencyCode + )} ${currencyCode}`, + subtotal: `${this.humanPrice_(subtotal, currencyCode)} ${currencyCode}`, + gift_card_total: `${this.humanPrice_( + gift_card_total, + currencyCode + )} ${currencyCode}`, + tax_total: `${this.humanPrice_(tax_total, currencyCode)} ${currencyCode}`, + discount_total: `${this.humanPrice_( + discountTotal, + currencyCode + )} ${currencyCode}`, + shipping_total: `${this.humanPrice_( + shipping_total, + currencyCode + )} ${currencyCode}`, + total: `${this.humanPrice_(total, currencyCode)} ${currencyCode}`, + } + } + async gcCreatedData({ id }) { const giftCard = await this.giftCardService_.retrieve(id, { relations: ["region", "order"], @@ -475,68 +600,76 @@ class SendGridService extends NotificationService { relations: [ "items", "items.item", + "items.item.tax_lines", "items.item.variant", "items.item.variant.product", "shipping_method", + "shipping_method.tax_lines", "shipping_method.shipping_option", ], }) - const items = await this.lineItemService_.list({ - id: returnRequest.items.map(({ item_id }) => item_id), - }) - - returnRequest.items = returnRequest.items.map((item) => { - const found = items.find((i) => i.id === item.item_id) - return { - ...item, - item: found, - } - }) + const items = await this.lineItemService_.list( + { + id: returnRequest.items.map(({ item_id }) => item_id), + }, + { relations: ["tax_lines"] } + ) // Fetch the order const order = await this.orderService_.retrieve(id, { select: ["total"], relations: [ "items", + "items.tax_lines", "discounts", "discounts.rule", "discounts.rule.valid_for", "shipping_address", "returns", - "swaps", - "swaps.additional_items", ], }) - let merged = [...order.items] - - // merge items from order with items from order swaps - if (order.swaps && order.swaps.length) { - for (const s of order.swaps) { - merged = [...merged, ...s.additional_items] - } - } - - // Calculate which items are in the return - const returnItems = returnRequest.items.map((i) => { - const found = merged.find((oi) => oi.id === i.item_id) - return { - ...found, - quantity: i.quantity, - } - }) - - const taxRate = order.tax_rate / 100 const currencyCode = order.currency_code.toUpperCase() + // Calculate which items are in the return + const returnItems = await Promise.all( + returnRequest.items.map(async (i) => { + const found = items.find((oi) => oi.id === i.item_id) + found.quantity = i.quantity + found.thumbnail = this.normalizeThumbUrl_(found.thumbnail) + found.totals = await this.totalsService_.getLineItemTotals( + found, + order, + { + include_tax: true, + use_tax_lines: true, + } + ) + found.price = `${this.humanPrice_( + found.totals.total, + currencyCode + )} ${currencyCode}` + found.tax_lines = found.totals.tax_lines + return found + }) + ) + // Get total of the returned products - const item_subtotal = this.totalsService_.getRefundTotal(order, returnItems) + const item_subtotal = returnItems.reduce( + (acc, next) => acc + next.totals.total, + 0 + ) // If the return has a shipping method get the price and any attachments let shippingTotal = 0 if (returnRequest.shipping_method) { - shippingTotal = returnRequest.shipping_method.price * (1 + taxRate) + const base = returnRequest.shipping_method.price + shippingTotal = + base + + returnRequest.shipping_method.tax_lines.reduce((acc, next) => { + return Math.round(acc + base * (next.rate / 100)) + }, 0) } const locale = await this.extractLocale(order) @@ -545,7 +678,7 @@ class SendGridService extends NotificationService { locale, has_shipping: !!returnRequest.shipping_method, email: order.email, - items: this.processItems_(returnItems, taxRate, currencyCode), + items: returnItems, subtotal: `${this.humanPrice_( item_subtotal, currencyCode @@ -570,11 +703,12 @@ class SendGridService extends NotificationService { } } - async swapCreatedData({ id }) { + async swapReceivedData({ id }) { const store = await this.storeService_.retrieve() const swap = await this.swapService_.retrieve(id, { relations: [ "additional_items", + "additional_items.tax_lines", "return_order", "return_order.items", "return_order.items.item", @@ -585,9 +719,14 @@ class SendGridService extends NotificationService { const returnRequest = swap.return_order - const items = await this.lineItemService_.list({ - id: returnRequest.items.map(({ item_id }) => item_id), - }) + const items = await this.lineItemService_.list( + { + id: returnRequest.items.map(({ item_id }) => item_id), + }, + { + relations: ["tax_lines"], + } + ) returnRequest.items = returnRequest.items.map((item) => { const found = items.find((i) => i.id === item.item_id) @@ -612,42 +751,51 @@ class SendGridService extends NotificationService { "shipping_address", "swaps", "swaps.additional_items", + "swaps.additional_items.tax_lines", ], }) - const taxRate = order.tax_rate / 100 + const cart = await this.cartService_.retrieve(swap.cart_id, { + select: [ + "total", + "tax_total", + "discount_total", + "shipping_total", + "subtotal", + ], + }) const currencyCode = order.currency_code.toUpperCase() - let merged = [...order.items] + const decoratedItems = await Promise.all( + cart.items.map(async (i) => { + const totals = await this.totalsService_.getLineItemTotals(i, cart, { + include_tax: true, + }) - // merge items from order with items from order swaps - if (order.swaps && order.swaps.length) { - for (const s of order.swaps) { - merged = [...merged, ...s.additional_items] - } - } - - const returnItems = this.processItems_( - swap.return_order.items.map((i) => { - const found = merged.find((oi) => oi.id === i.item_id) return { - ...found, - quantity: i.quantity, + ...i, + totals, + price: this.humanPrice_( + totals.subtotal + totals.tax_total, + currencyCode + ), } - }), - taxRate, - currencyCode + }) ) - const returnTotal = this.totalsService_.getRefundTotal(order, returnItems) + const returnTotal = decoratedItems.reduce((acc, next) => { + if (next.is_return) { + return acc + -1 * (next.totals.subtotal + next.totals.tax_total) + } + return acc + }, 0) - const constructedOrder = { - ...order, - shipping_methods: [], - items: swap.additional_items, - } - - const additionalTotal = this.totalsService_.getTotal(constructedOrder) + const additionalTotal = decoratedItems.reduce((acc, next) => { + if (!next.is_return) { + return acc + next.totals.subtotal + next.totals.tax_total + } + return acc + }, 0) const refundAmount = swap.return_order.refund_amount @@ -661,8 +809,143 @@ class SendGridService extends NotificationService { date: swap.updated_at.toDateString(), swap_link: swapLink, email: order.email, - items: this.processItems_(swap.additional_items, taxRate, currencyCode), - return_items: returnItems, + items: decoratedItems.filter((di) => !di.is_return), + return_items: decoratedItems.filter((di) => di.is_return), + return_total: `${this.humanPrice_( + returnTotal, + currencyCode + )} ${currencyCode}`, + tax_total: `${this.humanPrice_( + cart.total, + currencyCode + )} ${currencyCode}`, + refund_amount: `${this.humanPrice_( + refundAmount, + currencyCode + )} ${currencyCode}`, + additional_total: `${this.humanPrice_( + additionalTotal, + currencyCode + )} ${currencyCode}`, + } + } + + async swapCreatedData({ id }) { + const store = await this.storeService_.retrieve() + const swap = await this.swapService_.retrieve(id, { + relations: [ + "additional_items", + "additional_items.tax_lines", + "return_order", + "return_order.items", + "return_order.items.item", + "return_order.shipping_method", + "return_order.shipping_method.shipping_option", + ], + }) + + const returnRequest = swap.return_order + + const items = await this.lineItemService_.list( + { + id: returnRequest.items.map(({ item_id }) => item_id), + }, + { + relations: ["tax_lines"], + } + ) + + returnRequest.items = returnRequest.items.map((item) => { + const found = items.find((i) => i.id === item.item_id) + return { + ...item, + item: found, + } + }) + + const swapLink = store.swap_link_template.replace( + /\{cart_id\}/, + swap.cart_id + ) + + const order = await this.orderService_.retrieve(swap.order_id, { + select: ["total"], + relations: [ + "items", + "items.tax_lines", + "discounts", + "discounts.rule", + "discounts.rule.valid_for", + "shipping_address", + "swaps", + "swaps.additional_items", + "swaps.additional_items.tax_lines", + ], + }) + + const cart = await this.cartService_.retrieve(swap.cart_id, { + select: [ + "total", + "tax_total", + "discount_total", + "shipping_total", + "subtotal", + ], + }) + const currencyCode = order.currency_code.toUpperCase() + + const decoratedItems = await Promise.all( + cart.items.map(async (i) => { + const totals = await this.totalsService_.getLineItemTotals(i, cart, { + include_tax: true, + }) + + return { + ...i, + totals, + tax_lines: totals.tax_lines, + price: `${this.humanPrice_( + totals.original_total / i.quantity, + currencyCode + )} ${currencyCode}`, + discounted_price: `${this.humanPrice_( + totals.total / i.quantity, + currencyCode + )} ${currencyCode}`, + } + }) + ) + + const returnTotal = decoratedItems.reduce((acc, next) => { + const { total } = next.totals + if (next.is_return && next.variant_id) { + return acc + -1 * total + } + return acc + }, 0) + + const additionalTotal = decoratedItems.reduce((acc, next) => { + const { total } = next.totals + if (!next.is_return) { + return acc + total + } + return acc + }, 0) + + const refundAmount = swap.return_order.refund_amount + + const locale = await this.extractLocale(order) + + return { + locale, + swap, + order, + return_request: returnRequest, + date: swap.updated_at.toDateString(), + swap_link: swapLink, + email: order.email, + items: decoratedItems.filter((di) => !di.is_return), + return_items: decoratedItems.filter((di) => di.is_return), return_total: `${this.humanPrice_( returnTotal, currencyCode @@ -687,7 +970,9 @@ class SendGridService extends NotificationService { relations: [ "shipping_address", "shipping_methods", + "shipping_methods.tax_lines", "additional_items", + "additional_items.tax_lines", "return_order", "return_order.items", ], @@ -695,40 +980,68 @@ class SendGridService extends NotificationService { const order = await this.orderService_.retrieve(swap.order_id, { relations: [ + "region", "items", + "items.tax_lines", "discounts", "discounts.rule", "discounts.rule.valid_for", "swaps", "swaps.additional_items", + "swaps.additional_items.tax_lines", ], }) - let merged = [...order.items] + const cart = await this.cartService_.retrieve(swap.cart_id, { + select: [ + "total", + "tax_total", + "discount_total", + "shipping_total", + "subtotal", + ], + }) - // merge items from order with items from order swaps - if (order.swaps && order.swaps.length) { - for (const s of order.swaps) { - merged = [...merged, ...s.additional_items] + const returnRequest = swap.return_order + const items = await this.lineItemService_.list( + { + id: returnRequest.items.map(({ item_id }) => item_id), + }, + { + relations: ["tax_lines"], } - } + ) const taxRate = order.tax_rate / 100 const currencyCode = order.currency_code.toUpperCase() - const returnItems = this.processItems_( - swap.return_order.items.map((i) => { - const found = merged.find((oi) => oi.id === i.item_id) + const returnItems = await Promise.all( + swap.return_order.items.map(async (i) => { + const found = items.find((oi) => oi.id === i.item_id) + const totals = await this.totalsService_.getLineItemTotals(i, cart, { + include_tax: true, + }) + return { ...found, + thumbnail: this.normalizeThumbUrl_(found.thumbnail), + price: `${this.humanPrice_( + totals.original_total / i.quantity, + currencyCode + )} ${currencyCode}`, + discounted_price: `${this.humanPrice_( + totals.total / i.quantity, + currencyCode + )} ${currencyCode}`, quantity: i.quantity, } - }), - taxRate, - currencyCode + }) ) - const returnTotal = this.totalsService_.getRefundTotal(order, returnItems) + const returnTotal = await this.totalsService_.getRefundTotal( + order, + returnItems + ) const constructedOrder = { ...order, @@ -736,7 +1049,7 @@ class SendGridService extends NotificationService { items: swap.additional_items, } - const additionalTotal = this.totalsService_.getTotal(constructedOrder) + const additionalTotal = await this.totalsService_.getTotal(constructedOrder) const refundAmount = swap.return_order.refund_amount @@ -750,11 +1063,31 @@ class SendGridService extends NotificationService { locale, swap, order, - items: this.processItems_(swap.additional_items, taxRate, currencyCode), + items: await Promise.all( + swap.additional_items.map(async (i) => { + const totals = await this.totalsService_.getLineItemTotals(i, cart, { + include_tax: true, + }) + + return { + ...i, + thumbnail: this.normalizeThumbUrl_(i.thumbnail), + price: `${this.humanPrice_( + totals.original_total / i.quantity, + currencyCode + )} ${currencyCode}`, + discounted_price: `${this.humanPrice_( + totals.total / i.quantity, + currencyCode + )} ${currencyCode}`, + quantity: i.quantity, + } + }) + ), date: swap.updated_at.toDateString(), email: order.email, tax_amount: `${this.humanPrice_( - swap.difference_due * taxRate, + cart.tax_total, currencyCode )} ${currencyCode}`, paid_total: `${this.humanPrice_( @@ -871,7 +1204,7 @@ class SendGridService extends NotificationService { if (fromOrder.cart_id) { try { const cart = await this.cartService_.retrieve(fromOrder.cart_id, { - select: ["context"], + select: ["id", "context"], }) if (cart.context && cart.context.locale) { diff --git a/packages/medusa-plugin-slack-notification/src/services/slack.js b/packages/medusa-plugin-slack-notification/src/services/slack.js index 0770f1c9db..16a404e409 100644 --- a/packages/medusa-plugin-slack-notification/src/services/slack.js +++ b/packages/medusa-plugin-slack-notification/src/services/slack.js @@ -61,8 +61,6 @@ class SlackService extends BaseService { const { subtotal, tax_total, discount_total, shipping_total, total } = order const currencyCode = order.currency_code.toUpperCase() - const taxRate = order.tax_rate / 100 - const getDisplayAmount = (amount) => { const humanAmount = humanizeAmount(amount, currencyCode) if (zeroDecimalCurrencies.includes(currencyCode.toLowerCase())) { @@ -141,13 +139,20 @@ class SlackService extends BaseService { type: "divider", }) - order.items.forEach((lineItem) => { + for (const lineItem of order.items) { + const totals = await this.totalsService_.getLineItemTotals( + lineItem, + order, + { + include_tax: true, + } + ) let line = { type: "section", text: { type: "mrkdwn", text: `*${lineItem.title}*\n${lineItem.quantity} x ${getDisplayAmount( - lineItem.unit_price * (1 + taxRate) + totals.original_total )} ${currencyCode}`, }, } @@ -170,7 +175,7 @@ class SlackService extends BaseService { blocks.push({ type: "divider", }) - }) + } return axios.post(this.options_.slack_url, { text: `Order ${order.display_id} was processed`, diff --git a/packages/medusa-react/src/hooks/admin/index.ts b/packages/medusa-react/src/hooks/admin/index.ts index c36cc5f3bd..b16812a9cb 100644 --- a/packages/medusa-react/src/hooks/admin/index.ts +++ b/packages/medusa-react/src/hooks/admin/index.ts @@ -8,6 +8,7 @@ export * from "./gift-cards" export * from "./orders" export * from "./products" export * from "./product-tags" +export * from "./product-types" export * from "./return-reasons" export * from "./regions" export * from "./shipping-options" @@ -20,3 +21,4 @@ export * from "./store" export * from "./swaps" export * from "./users" export * from "./variants" +export * from "./tax-rates" diff --git a/packages/medusa-react/src/hooks/admin/product-types/index.ts b/packages/medusa-react/src/hooks/admin/product-types/index.ts new file mode 100644 index 0000000000..f3593df2df --- /dev/null +++ b/packages/medusa-react/src/hooks/admin/product-types/index.ts @@ -0,0 +1 @@ +export * from "./queries" diff --git a/packages/medusa-react/src/hooks/admin/product-types/queries.ts b/packages/medusa-react/src/hooks/admin/product-types/queries.ts new file mode 100644 index 0000000000..97da888a42 --- /dev/null +++ b/packages/medusa-react/src/hooks/admin/product-types/queries.ts @@ -0,0 +1,34 @@ +import { + AdminProductTypesListRes, + AdminGetProductTypesParams, +} from "@medusajs/medusa" +import { Response } from "@medusajs/medusa-js" +import { useQuery } from "react-query" +import { useMedusa } from "../../../contexts" +import { UseQueryOptionsWrapper } from "../../../types" +import { queryKeysFactory } from "../../utils/index" + +const ADMIN_PRODUCT_TYPES_QUERY_KEY = `admin_product_types` as const + +export const adminProductTypeKeys = queryKeysFactory( + ADMIN_PRODUCT_TYPES_QUERY_KEY +) + +type ProductTypesQueryKeys = typeof adminProductTypeKeys + +export const useAdminProductTypes = ( + query?: AdminGetProductTypesParams, + options?: UseQueryOptionsWrapper< + Response, + Error, + ReturnType + > +) => { + const { client } = useMedusa() + const { data, ...rest } = useQuery( + adminProductTypeKeys.list(query), + () => client.admin.productTypes.list(query), + options + ) + return { ...data, ...rest } as const +} diff --git a/packages/medusa-react/src/hooks/admin/products/queries.ts b/packages/medusa-react/src/hooks/admin/products/queries.ts index 759856e6bc..5d50640068 100644 --- a/packages/medusa-react/src/hooks/admin/products/queries.ts +++ b/packages/medusa-react/src/hooks/admin/products/queries.ts @@ -2,7 +2,6 @@ import { AdminProductsListRes, AdminProductsRes, AdminGetProductsParams, - AdminProductsListTypesRes, AdminProductsListTagsRes, } from "@medusajs/medusa" import { Response } from "@medusajs/medusa-js" @@ -51,22 +50,6 @@ export const useAdminProduct = ( return { ...data, ...rest } as const } -export const useAdminProductTypes = ( - options?: UseQueryOptionsWrapper< - Response, - Error, - ReturnType - > -) => { - const { client } = useMedusa() - const { data, ...rest } = useQuery( - adminProductKeys.detail("types"), - () => client.admin.products.listTypes(), - options - ) - return { ...data, ...rest } as const -} - export const useAdminProductTagUsage = ( options?: UseQueryOptionsWrapper< Response, diff --git a/packages/medusa-react/src/hooks/admin/store/queries.ts b/packages/medusa-react/src/hooks/admin/store/queries.ts index 5e8eaf52dd..3cae782408 100644 --- a/packages/medusa-react/src/hooks/admin/store/queries.ts +++ b/packages/medusa-react/src/hooks/admin/store/queries.ts @@ -1,4 +1,8 @@ -import { AdminPaymentProvidersList, AdminStoresRes } from "@medusajs/medusa" +import { + AdminTaxProvidersList, + AdminPaymentProvidersList, + AdminStoresRes, +} from "@medusajs/medusa" import { Response } from "@medusajs/medusa-js" import { useQuery } from "react-query" import { useMedusa } from "../../../contexts" @@ -27,6 +31,22 @@ export const useAdminStorePaymentProviders = ( return { ...data, ...rest } as const } +export const useAdminStoreTaxProviders = ( + options?: UseQueryOptionsWrapper< + Response, + Error, + ReturnType + > +) => { + const { client } = useMedusa() + const { data, ...rest } = useQuery( + adminStoreKeys.detail("tax_providers"), + () => client.admin.store.listTaxProviders(), + options + ) + return { ...data, ...rest } as const +} + export const useAdminStore = ( options?: UseQueryOptionsWrapper< Response, diff --git a/packages/medusa-react/src/hooks/admin/tax-rates/index.ts b/packages/medusa-react/src/hooks/admin/tax-rates/index.ts new file mode 100644 index 0000000000..a494946b87 --- /dev/null +++ b/packages/medusa-react/src/hooks/admin/tax-rates/index.ts @@ -0,0 +1,2 @@ +export * from "./queries" +export * from "./mutations" diff --git a/packages/medusa-react/src/hooks/admin/tax-rates/mutations.ts b/packages/medusa-react/src/hooks/admin/tax-rates/mutations.ts new file mode 100644 index 0000000000..39fbb09bf7 --- /dev/null +++ b/packages/medusa-react/src/hooks/admin/tax-rates/mutations.ts @@ -0,0 +1,203 @@ +import { adminTaxRateKeys } from "./queries" +import { + AdminTaxRatesRes, + AdminTaxRatesDeleteRes, + AdminDeleteTaxRatesTaxRateProductsReq, + AdminDeleteTaxRatesTaxRateProductTypesReq, + AdminDeleteTaxRatesTaxRateShippingOptionsReq, + AdminPostTaxRatesReq, + AdminPostTaxRatesTaxRateReq, + AdminPostTaxRatesTaxRateProductsReq, + AdminPostTaxRatesTaxRateProductTypesReq, + AdminPostTaxRatesTaxRateShippingOptionsReq, +} from "@medusajs/medusa" +import { Response } from "@medusajs/medusa-js" +import { useMutation, UseMutationOptions, useQueryClient } from "react-query" +import { useMedusa } from "../../../contexts/medusa" +import { buildOptions } from "../../utils/buildOptions" + +export const useAdminCreateTaxRate = ( + options?: UseMutationOptions< + Response, + Error, + AdminPostTaxRatesReq + > +) => { + const { client } = useMedusa() + const queryClient = useQueryClient() + return useMutation( + (payload: AdminPostTaxRatesReq) => client.admin.taxRates.create(payload), + buildOptions(queryClient, adminTaxRateKeys.lists(), options) + ) +} + +export const useAdminUpdateTaxRate = ( + id: string, + options?: UseMutationOptions< + Response, + Error, + AdminPostTaxRatesTaxRateReq + > +) => { + const { client } = useMedusa() + const queryClient = useQueryClient() + + return useMutation( + (payload: AdminPostTaxRatesTaxRateReq) => + client.admin.taxRates.update(id, payload), + buildOptions( + queryClient, + [adminTaxRateKeys.lists(), adminTaxRateKeys.detail(id)], + options + ) + ) +} + +export const useAdminDeleteTaxRate = ( + id: string, + options?: UseMutationOptions, Error, void> +) => { + const { client } = useMedusa() + const queryClient = useQueryClient() + + return useMutation( + () => client.admin.taxRates.delete(id), + buildOptions( + queryClient, + [adminTaxRateKeys.lists(), adminTaxRateKeys.detail(id)], + options + ) + ) +} + +export const useAdminCreateProductTaxRates = ( + id: string, + options?: UseMutationOptions< + Response, + Error, + AdminPostTaxRatesTaxRateProductsReq + > +) => { + const { client } = useMedusa() + const queryClient = useQueryClient() + + return useMutation( + (payload: AdminPostTaxRatesTaxRateProductsReq) => + client.admin.taxRates.addProducts(id, payload), + buildOptions( + queryClient, + [adminTaxRateKeys.lists(), adminTaxRateKeys.detail(id)], + options + ) + ) +} + +export const useAdminDeleteProductTaxRates = ( + id: string, + options?: UseMutationOptions< + Response, + Error, + AdminDeleteTaxRatesTaxRateProductsReq + > +) => { + const { client } = useMedusa() + const queryClient = useQueryClient() + + return useMutation( + (payload: AdminDeleteTaxRatesTaxRateProductsReq) => + client.admin.taxRates.removeProducts(id, payload), + buildOptions( + queryClient, + [adminTaxRateKeys.lists(), adminTaxRateKeys.detail(id)], + options + ) + ) +} + +export const useAdminCreateProductTypeTaxRates = ( + id: string, + options?: UseMutationOptions< + Response, + Error, + AdminPostTaxRatesTaxRateProductTypesReq + > +) => { + const { client } = useMedusa() + const queryClient = useQueryClient() + + return useMutation( + (payload: AdminPostTaxRatesTaxRateProductTypesReq) => + client.admin.taxRates.addProductTypes(id, payload), + buildOptions( + queryClient, + [adminTaxRateKeys.lists(), adminTaxRateKeys.detail(id)], + options + ) + ) +} + +export const useAdminDeleteProductTypeTaxRates = ( + id: string, + options?: UseMutationOptions< + Response, + Error, + AdminDeleteTaxRatesTaxRateProductTypesReq + > +) => { + const { client } = useMedusa() + const queryClient = useQueryClient() + + return useMutation( + (payload: AdminDeleteTaxRatesTaxRateProductTypesReq) => + client.admin.taxRates.removeProductTypes(id, payload), + buildOptions( + queryClient, + [adminTaxRateKeys.lists(), adminTaxRateKeys.detail(id)], + options + ) + ) +} + +export const useAdminCreateShippingTaxRates = ( + id: string, + options?: UseMutationOptions< + Response, + Error, + AdminPostTaxRatesTaxRateShippingOptionsReq + > +) => { + const { client } = useMedusa() + const queryClient = useQueryClient() + + return useMutation( + (payload: AdminPostTaxRatesTaxRateShippingOptionsReq) => + client.admin.taxRates.addShippingOptions(id, payload), + buildOptions( + queryClient, + [adminTaxRateKeys.lists(), adminTaxRateKeys.detail(id)], + options + ) + ) +} + +export const useAdminDeleteShippingTaxRates = ( + id: string, + options?: UseMutationOptions< + Response, + Error, + AdminDeleteTaxRatesTaxRateShippingOptionsReq + > +) => { + const { client } = useMedusa() + const queryClient = useQueryClient() + + return useMutation( + (payload: AdminDeleteTaxRatesTaxRateShippingOptionsReq) => + client.admin.taxRates.removeShippingOptions(id, payload), + buildOptions( + queryClient, + [adminTaxRateKeys.lists(), adminTaxRateKeys.detail(id)], + options + ) + ) +} diff --git a/packages/medusa-react/src/hooks/admin/tax-rates/queries.ts b/packages/medusa-react/src/hooks/admin/tax-rates/queries.ts new file mode 100644 index 0000000000..f389fbf30e --- /dev/null +++ b/packages/medusa-react/src/hooks/admin/tax-rates/queries.ts @@ -0,0 +1,51 @@ +import { + AdminTaxRatesRes, + AdminTaxRatesListRes, + AdminGetTaxRatesParams, +} from "@medusajs/medusa" +import { Response } from "@medusajs/medusa-js" +import { useQuery } from "react-query" +import { useMedusa } from "../../../contexts" +import { UseQueryOptionsWrapper } from "../../../types" +import { queryKeysFactory } from "../../utils/index" + +const ADMIN_TAX_RATES_QUERY_KEY = `admin_tax_rates` as const + +export const adminTaxRateKeys = queryKeysFactory(ADMIN_TAX_RATES_QUERY_KEY) + +type TaxRateQueryKeys = typeof adminTaxRateKeys + +export const useAdminTaxRates = ( + query?: AdminGetTaxRatesParams, + options?: UseQueryOptionsWrapper< + Response, + Error, + ReturnType + > +) => { + const { client } = useMedusa() + const { data, ...rest } = useQuery( + adminTaxRateKeys.list(query), + () => client.admin.taxRates.list(query), + options + ) + return { ...data, ...rest } as const +} + +export const useAdminTaxRate = ( + id: string, + query?: AdminGetTaxRatesParams, + options?: UseQueryOptionsWrapper< + Response, + Error, + ReturnType + > +) => { + const { client } = useMedusa() + const { data, ...rest } = useQuery( + adminTaxRateKeys.detail(id), + () => client.admin.taxRates.retrieve(id, query), + options + ) + return { ...data, ...rest } as const +} diff --git a/packages/medusa-react/test/hooks/admin/products/queries.test.ts b/packages/medusa-react/test/hooks/admin/products/queries.test.ts index 769a4634c6..3c8a32112e 100644 --- a/packages/medusa-react/test/hooks/admin/products/queries.test.ts +++ b/packages/medusa-react/test/hooks/admin/products/queries.test.ts @@ -22,20 +22,6 @@ describe("useAdminProducts hook", () => { }) }) -describe("useAdminProductTypes hook", () => { - test("returns a list of product types", async () => { - const types = fixtures.list("product_type") - const { result, waitFor } = renderHook(() => useAdminProductTypes(), { - wrapper: createWrapper(), - }) - - await waitFor(() => result.current.isSuccess) - - expect(result.current.response.status).toEqual(200) - expect(result.current.types).toEqual(types) - }) -}) - describe("useAdminProductTagUsage hook", () => { test("returns a list of product tags", async () => { const tags = fixtures.list("product_tag") diff --git a/packages/medusa-react/test/hooks/admin/swaps/mutations.test.ts b/packages/medusa-react/test/hooks/admin/swaps/mutations.test.ts index 59d5364531..a6bf100348 100644 --- a/packages/medusa-react/test/hooks/admin/swaps/mutations.test.ts +++ b/packages/medusa-react/test/hooks/admin/swaps/mutations.test.ts @@ -1,6 +1,8 @@ import { renderHook } from "@testing-library/react-hooks" import { fixtures } from "../../../../mocks/data" import { + useAdminCreateSwap, + useAdminFulfillSwap, useAdminCancelSwap, useAdminCancelSwapFulfillment, useAdminCreateSwap, diff --git a/packages/medusa/package.json b/packages/medusa/package.json index a40f084137..cfe8727eb4 100644 --- a/packages/medusa/package.json +++ b/packages/medusa/package.json @@ -21,6 +21,7 @@ "@babel/core": "^7.14.3", "@babel/preset-typescript": "^7.13.0", "@types/express": "^4.17.13", + "@types/jest": "^27.0.3", "@types/jsonwebtoken": "^8.5.5", "babel-preset-medusa-package": "^1.1.19", "cross-env": "^5.2.1", diff --git a/packages/medusa/src/api/index.js b/packages/medusa/src/api/index.js index da7d036f6f..90235c6029 100644 --- a/packages/medusa/src/api/index.js +++ b/packages/medusa/src/api/index.js @@ -35,9 +35,11 @@ export * from "./routes/admin/return-reasons" export * from "./routes/admin/swaps" export * from "./routes/admin/uploads" export * from "./routes/admin/returns" +export * from "./routes/admin/tax-rates" export * from "./routes/admin/shipping-options" export * from "./routes/admin/regions" export * from "./routes/admin/product-tags" +export * from "./routes/admin/product-types" // Store export * from "./routes/store/auth" diff --git a/packages/medusa/src/api/routes/admin/index.js b/packages/medusa/src/api/routes/admin/index.js index 1e07b32c79..b5e4107b7c 100644 --- a/packages/medusa/src/api/routes/admin/index.js +++ b/packages/medusa/src/api/routes/admin/index.js @@ -25,6 +25,8 @@ import collectionRoutes from "./collections" import productTagRoutes from "./product-tags" import notificationRoutes from "./notifications" import noteRoutes from "./notes" +import taxRateRoutes from "./tax-rates" +import productTypesRoutes from "./product-types" import customerGroupRoutes from "./customer-groups" const route = Router() @@ -79,8 +81,10 @@ export default (app, container, config) => { notificationRoutes(route) returnReasonRoutes(route) productTagRoutes(route) + productTypesRoutes(route) noteRoutes(route) inviteRoutes(route) + taxRateRoutes(route) customerGroupRoutes(route) return app diff --git a/packages/medusa/src/api/routes/admin/orders/__tests__/get-order.js b/packages/medusa/src/api/routes/admin/orders/__tests__/get-order.js index c2c31b630e..3b70832f6a 100644 --- a/packages/medusa/src/api/routes/admin/orders/__tests__/get-order.js +++ b/packages/medusa/src/api/routes/admin/orders/__tests__/get-order.js @@ -15,6 +15,8 @@ const defaultRelations = [ "fulfillments.tracking_links", "fulfillments.items", "returns", + "returns.shipping_method", + "returns.shipping_method.tax_lines", "returns.items", "returns.items.reason", "gift_cards", diff --git a/packages/medusa/src/api/routes/admin/orders/create-claim.ts b/packages/medusa/src/api/routes/admin/orders/create-claim.ts index 3b9bb55c8b..11fbab6049 100644 --- a/packages/medusa/src/api/routes/admin/orders/create-claim.ts +++ b/packages/medusa/src/api/routes/admin/orders/create-claim.ts @@ -169,7 +169,15 @@ export default async (req, res) => { const order = await orderService .withTransaction(manager) .retrieve(id, { - relations: ["items", "discounts", "discounts.rule"], + relations: [ + "customer", + "shipping_address", + "region", + "items", + "items.tax_lines", + "discounts", + "discounts.rule", + ], }) await claimService.withTransaction(manager).create({ diff --git a/packages/medusa/src/api/routes/admin/orders/create-swap-shipment.ts b/packages/medusa/src/api/routes/admin/orders/create-swap-shipment.ts index 1fea91d769..4c815491a3 100644 --- a/packages/medusa/src/api/routes/admin/orders/create-swap-shipment.ts +++ b/packages/medusa/src/api/routes/admin/orders/create-swap-shipment.ts @@ -81,7 +81,7 @@ export class AdminPostOrdersOrderSwapsSwapShipmentsReq { @IsArray() @IsOptional() @IsString({ each: true }) - tracking_numbers?: string[] + tracking_numbers?: string[] = [] @IsBoolean() @IsOptional() diff --git a/packages/medusa/src/api/routes/admin/orders/create-swap.ts b/packages/medusa/src/api/routes/admin/orders/create-swap.ts index a9c4f04378..7b21f5b58c 100644 --- a/packages/medusa/src/api/routes/admin/orders/create-swap.ts +++ b/packages/medusa/src/api/routes/admin/orders/create-swap.ts @@ -150,7 +150,13 @@ export default async (req, res) => { .withTransaction(manager) .retrieve(id, { select: ["refunded_total", "total"], - relations: ["items", "swaps", "swaps.additional_items"], + relations: [ + "items", + "items.tax_lines", + "swaps", + "swaps.additional_items", + "swaps.additional_items.tax_lines", + ], }) const swap = await swapService @@ -170,6 +176,7 @@ export default async (req, res) => { await swapService .withTransaction(manager) .createCart(swap.id, validated.custom_shipping_options) + const returnOrder = await returnService .withTransaction(manager) .retrieveBySwap(swap.id) diff --git a/packages/medusa/src/api/routes/admin/orders/index.ts b/packages/medusa/src/api/routes/admin/orders/index.ts index 374fd828ff..a1600cc654 100644 --- a/packages/medusa/src/api/routes/admin/orders/index.ts +++ b/packages/medusa/src/api/routes/admin/orders/index.ts @@ -143,14 +143,6 @@ export default (app) => { middlewares.wrap(require("./cancel-swap").default) ) - /** - * Receives the inventory to return from a swap - */ - route.post( - "/:id/swaps/:swap_id/receive", - middlewares.wrap(require("./receive-swap").default) - ) - /** * Fulfills a swap. */ @@ -246,6 +238,8 @@ export const defaultAdminOrdersRelations = [ "fulfillments.tracking_links", "fulfillments.items", "returns", + "returns.shipping_method", + "returns.shipping_method.tax_lines", "returns.items", "returns.items.reason", "gift_cards", @@ -390,7 +384,6 @@ export * from "./fulfill-swap" export * from "./get-order" export * from "./list-orders" export * from "./process-swap-payment" -export * from "./receive-swap" export * from "./refund-payment" export * from "./request-return" export * from "./update-claim" diff --git a/packages/medusa/src/api/routes/admin/orders/receive-swap.ts b/packages/medusa/src/api/routes/admin/orders/receive-swap.ts deleted file mode 100644 index c955883269..0000000000 --- a/packages/medusa/src/api/routes/admin/orders/receive-swap.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { Type } from "class-transformer" -import { - IsArray, - IsInt, - IsNotEmpty, - IsString, - ValidateNested, -} from "class-validator" -import { EntityManager } from "typeorm" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." -import { OrderService, SwapService } from "../../../../services" -import { validator } from "../../../../utils/validator" -/** - * @oas [post] /orders/{id}/swaps/{swap_id}/receive - * operationId: "PostOrdersOrderSwapsSwapReceive" - * summary: "Receive a Swap" - * description: "Registers a Swap as received." - * x-authenticated: true - * parameters: - * - (path) id=* {string} The id of the Order. - * - (path) swap_id=* {string} The id of the Swap. - * requestBody: - * content: - * application/json: - * schema: - * properties: - * items: - * description: The Line Items that have been received. - * type: array - * items: - * properties: - * item_id: - * description: The id of the Line Item. - * type: string - * quantity: - * description: The quantity of the Line Item. - * type: integer - * tags: - * - Order - * responses: - * 200: - * description: OK - * content: - * application/json: - * schema: - * properties: - * order: - * $ref: "#/components/schemas/order" - */ -export default async (req, res) => { - const { id, swap_id } = req.params - - const validated = await validator( - AdminPostOrdersOrderSwapsSwapReceiveReq, - req.body - ) - - const orderService: OrderService = req.scope.resolve("orderService") - const swapService: SwapService = req.scope.resolve("swapService") - const entityManager: EntityManager = req.scope.resolve("manager") - - await entityManager.transaction(async (manager) => { - await swapService - .withTransaction(manager) - .receiveReturn(swap_id, validated.items) - - await orderService - .withTransaction(manager) - .registerSwapReceived(id, swap_id) - }) - - const order = await orderService.retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, - }) - - res.status(200).json({ order }) -} - -export class AdminPostOrdersOrderSwapsSwapReceiveReq { - @IsArray() - @ValidateNested({ each: true }) - @Type(() => Item) - items: Item[] -} - -class Item { - @IsString() - @IsNotEmpty() - item_id: string - - @IsInt() - @IsNotEmpty() - quantity: number -} diff --git a/packages/medusa/src/api/routes/admin/product-types/index.ts b/packages/medusa/src/api/routes/admin/product-types/index.ts new file mode 100644 index 0000000000..1f35e7e886 --- /dev/null +++ b/packages/medusa/src/api/routes/admin/product-types/index.ts @@ -0,0 +1,40 @@ +import { Router } from "express" +import { ProductType } from "../../../.." +import { PaginatedResponse } from "../../../../types/common" +import middlewares from "../../../middlewares" +import "reflect-metadata" + +const route = Router() + +export default (app) => { + app.use("/product-types", route) + + route.get("/", middlewares.wrap(require("./list-product-types").default)) + + return app +} + +export const allowedAdminProductTypeFields = [ + "id", + "value", + "created_at", + "updated_at", +] + +export const defaultAdminProductTypeFields = [ + "id", + "value", + "created_at", + "updated_at", +] +export const defaultAdminProductTypeRelations = [] + +export type AdminProductTypesListRes = PaginatedResponse & { + product_types: ProductType[] +} + +export type AdminProductTypesRes = { + product_type: ProductType +} + +export * from "./list-product-types" diff --git a/packages/medusa/src/api/routes/admin/product-types/list-product-types.ts b/packages/medusa/src/api/routes/admin/product-types/list-product-types.ts new file mode 100644 index 0000000000..215baed4b2 --- /dev/null +++ b/packages/medusa/src/api/routes/admin/product-types/list-product-types.ts @@ -0,0 +1,125 @@ +import { Type } from "class-transformer" +import { MedusaError } from "medusa-core-utils" +import { IsNumber, IsString, IsOptional, ValidateNested } from "class-validator" +import { omit, pickBy, identity } from "lodash" +import { + allowedAdminProductTypeFields, + defaultAdminProductTypeFields, + defaultAdminProductTypeRelations, +} from "." +import { ProductType } from "../../../../models/product-type" +import ProductTypeService from "../../../../services/product-type" +import { + StringComparisonOperator, + DateComparisonOperator, + FindConfig, +} from "../../../../types/common" +import { validator } from "../../../../utils/validator" +import { IsType } from "../../../../utils/validators/is-type" + +/** + * @oas [get] /product-types + * operationId: "GetProductTypes" + * summary: "List Product Types" + * description: "Retrieve a list of Product Types." + * x-authenticated: true + * parameters: + * - (query) limit {string} The number of types to return. + * - (query) offset {string} The offset of types to return. + * - (query) value {string} The value of types to return. + * - (query) id {string} The id of types to return. + * - (query) created_at {DateComparisonOperator} Date comparison for when resulting tas was created, i.e. less than, greater than etc. + * - (query) updated_at {DateComparisonOperator} Date comparison for when resulting tas was updated, i.e. less than, greater than etc. + * tags: + * - Product Tag + * responses: + * "200": + * description: OK + * content: + * application/json: + * schema: + * properties: + * types: + * $ref: "#/components/schemas/product_tag" + */ +export default async (req, res) => { + const validated = await validator(AdminGetProductTypesParams, req.query) + + const typeService: ProductTypeService = + req.scope.resolve("productTypeService") + + const listConfig: FindConfig = { + select: defaultAdminProductTypeFields as (keyof ProductType)[], + relations: defaultAdminProductTypeRelations, + skip: validated.offset, + take: validated.limit, + } + + if (typeof validated.order !== "undefined") { + let orderField = validated.order + if (validated.order.startsWith("-")) { + const [, field] = validated.order.split("-") + orderField = field + listConfig.order = { [field]: "DESC" } + } else { + listConfig.order = { [validated.order]: "ASC" } + } + + if (!allowedAdminProductTypeFields.includes(orderField)) { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + "Order field must be a valid product type field" + ) + } + } + + const filterableFields = omit(validated, ["limit", "offset"]) + + const [types, count] = await typeService.listAndCount( + pickBy(filterableFields, identity), + listConfig + ) + + res.status(200).json({ + product_types: types, + count, + offset: validated.offset, + limit: validated.limit, + }) +} + +export class AdminGetProductTypesPaginationParams { + @IsNumber() + @IsOptional() + @Type(() => Number) + limit? = 10 + + @IsNumber() + @IsOptional() + @Type(() => Number) + offset? = 0 +} + +export class AdminGetProductTypesParams extends AdminGetProductTypesPaginationParams { + @ValidateNested() + @IsType([String, [String], StringComparisonOperator]) + @IsOptional() + id?: string | string[] | StringComparisonOperator + + @ValidateNested() + @IsType([String, [String], StringComparisonOperator]) + @IsOptional() + value?: string | string[] | StringComparisonOperator + + @IsType([DateComparisonOperator]) + @IsOptional() + created_at?: DateComparisonOperator + + @IsType([DateComparisonOperator]) + @IsOptional() + updated_at?: DateComparisonOperator + + @IsString() + @IsOptional() + order?: string +} diff --git a/packages/medusa/src/api/routes/admin/regions/__tests__/get-region.js b/packages/medusa/src/api/routes/admin/regions/__tests__/get-region.js index 4d0d8fc4cb..be98d8ed07 100644 --- a/packages/medusa/src/api/routes/admin/regions/__tests__/get-region.js +++ b/packages/medusa/src/api/routes/admin/regions/__tests__/get-region.js @@ -5,6 +5,9 @@ import { RegionServiceMock } from "../../../../../services/__mocks__/region" const defaultFields = [ "id", "name", + "automatic_taxes", + "gift_cards_taxable", + "tax_provider_id", "currency_code", "tax_rate", "tax_code", diff --git a/packages/medusa/src/api/routes/admin/regions/__tests__/list-regions.js b/packages/medusa/src/api/routes/admin/regions/__tests__/list-regions.js index 0461e3365a..f4cd6b3fce 100644 --- a/packages/medusa/src/api/routes/admin/regions/__tests__/list-regions.js +++ b/packages/medusa/src/api/routes/admin/regions/__tests__/list-regions.js @@ -5,6 +5,9 @@ import { RegionServiceMock } from "../../../../../services/__mocks__/region" const defaultFields = [ "id", "name", + "automatic_taxes", + "gift_cards_taxable", + "tax_provider_id", "currency_code", "tax_rate", "tax_code", diff --git a/packages/medusa/src/api/routes/admin/regions/index.ts b/packages/medusa/src/api/routes/admin/regions/index.ts index 062832aa10..1b5780dfc2 100644 --- a/packages/medusa/src/api/routes/admin/regions/index.ts +++ b/packages/medusa/src/api/routes/admin/regions/index.ts @@ -77,6 +77,9 @@ export default (app) => { export const defaultAdminRegionFields = [ "id", "name", + "automatic_taxes", + "gift_cards_taxable", + "tax_provider_id", "currency_code", "tax_rate", "tax_code", diff --git a/packages/medusa/src/api/routes/admin/regions/update-region.ts b/packages/medusa/src/api/routes/admin/regions/update-region.ts index e7f1e26bc4..3d727c7869 100644 --- a/packages/medusa/src/api/routes/admin/regions/update-region.ts +++ b/packages/medusa/src/api/routes/admin/regions/update-region.ts @@ -1,4 +1,10 @@ -import { IsArray, IsNumber, IsOptional, IsString } from "class-validator" +import { + IsArray, + IsBoolean, + IsNumber, + IsOptional, + IsString, +} from "class-validator" import { defaultAdminRegionRelations, defaultAdminRegionFields } from "." import { validator } from "../../../../utils/validator" import RegionService from "../../../../services/region" @@ -22,6 +28,15 @@ import RegionService from "../../../../services/region" * currency_code: * description: "The 3 character ISO currency code to use for the Region." * type: string + * automatic_taxes: + * description: "If true Medusa will automatically calculate taxes for carts in this region. If false you have to manually call POST /carts/:id/taxes." + * type: boolean + * gift_cards_taxable: + * description: "Whether gift cards in this region should be applied sales tax when purchasing a gift card" + * type: boolean + * tax_provider_id: + * description: "The id of the tax provider to use; if null the system tax provider is used" + * type: string * tax_code: * description: "An optional tax code the Region." * type: string @@ -86,6 +101,18 @@ export class AdminPostRegionsRegionReq { @IsOptional() tax_rate?: number + @IsBoolean() + @IsOptional() + gift_cards_taxable?: boolean + + @IsBoolean() + @IsOptional() + automatic_taxes?: boolean + + @IsString() + @IsOptional() + tax_provider_id?: string | null + @IsArray() @IsString({ each: true }) @IsOptional() diff --git a/packages/medusa/src/api/routes/admin/shipping-options/__tests__/list-shipping-options.js b/packages/medusa/src/api/routes/admin/shipping-options/__tests__/list-shipping-options.js index 0c163a3c40..37069279ff 100644 --- a/packages/medusa/src/api/routes/admin/shipping-options/__tests__/list-shipping-options.js +++ b/packages/medusa/src/api/routes/admin/shipping-options/__tests__/list-shipping-options.js @@ -40,8 +40,8 @@ describe("GET /admin/shipping-options", () => { }) it("calls service retrieve", () => { - expect(ShippingOptionServiceMock.list).toHaveBeenCalledTimes(1) - expect(ShippingOptionServiceMock.list).toHaveBeenCalledWith( + expect(ShippingOptionServiceMock.listAndCount).toHaveBeenCalledTimes(1) + expect(ShippingOptionServiceMock.listAndCount).toHaveBeenCalledWith( {}, { select: defaultFields, diff --git a/packages/medusa/src/api/routes/admin/shipping-options/index.ts b/packages/medusa/src/api/routes/admin/shipping-options/index.ts index 30fce989d1..58055c2e6d 100644 --- a/packages/medusa/src/api/routes/admin/shipping-options/index.ts +++ b/packages/medusa/src/api/routes/admin/shipping-options/index.ts @@ -1,6 +1,6 @@ import { Router } from "express" import { ShippingOption } from "../../../.." -import { DeleteResponse } from "../../../../types/common" +import { PaginatedResponse, DeleteResponse } from "../../../../types/common" import middlewares from "../../../middlewares" const route = Router() @@ -46,7 +46,7 @@ export const defaultFields = [ export const defaultRelations = ["region", "profile", "requirements"] -export type AdminShippingOptionsListRes = { +export type AdminShippingOptionsListRes = PaginatedResponse & { shipping_options: ShippingOption[] } diff --git a/packages/medusa/src/api/routes/admin/shipping-options/list-shipping-options.ts b/packages/medusa/src/api/routes/admin/shipping-options/list-shipping-options.ts index 8e2e0cbda4..bc7c15a046 100644 --- a/packages/medusa/src/api/routes/admin/shipping-options/list-shipping-options.ts +++ b/packages/medusa/src/api/routes/admin/shipping-options/list-shipping-options.ts @@ -50,12 +50,12 @@ export default async (req, res) => { ) const optionService = req.scope.resolve("shippingOptionService") - const data = await optionService.list(validatedParams, { + const [data, count] = await optionService.listAndCount(validatedParams, { select: defaultFields, relations: defaultRelations, }) - res.status(200).json({ shipping_options: data }) + res.status(200).json({ shipping_options: data, count }) } export class AdminGetShippingOptionsParams { diff --git a/packages/medusa/src/api/routes/admin/store/index.ts b/packages/medusa/src/api/routes/admin/store/index.ts index a9234a00f2..991e68aeb9 100644 --- a/packages/medusa/src/api/routes/admin/store/index.ts +++ b/packages/medusa/src/api/routes/admin/store/index.ts @@ -1,5 +1,5 @@ import { Router } from "express" -import { Store, PaymentProvider } from "./../../../../" +import { Store, PaymentProvider, TaxProvider } from "./../../../../" import middlewares from "../../../middlewares" const route = Router() @@ -12,6 +12,10 @@ export default (app) => { "/payment-providers", middlewares.wrap(require("./list-payment-providers").default) ) + route.get( + "/tax-providers", + middlewares.wrap(require("./list-tax-providers").default) + ) route.post("/", middlewares.wrap(require("./update-store").default)) route.post( "/currencies/:currency_code", @@ -29,6 +33,10 @@ export type AdminStoresRes = { store: Store } +export type AdminTaxProvidersList = { + tax_providers: TaxProvider[] +} + export type AdminPaymentProvidersList = { payment_providers: PaymentProvider[] } diff --git a/packages/medusa/src/api/routes/admin/store/list-tax-providers.ts b/packages/medusa/src/api/routes/admin/store/list-tax-providers.ts new file mode 100644 index 0000000000..9c9674cda6 --- /dev/null +++ b/packages/medusa/src/api/routes/admin/store/list-tax-providers.ts @@ -0,0 +1,28 @@ +import { TaxProviderService } from "../../../../services" + +/** + * @oas [get] /store/tax-providers + * operationId: "GetStoreTaxProviders" + * summary: "Retrieve configured Tax Providers" + * description: "Retrieves the configured Tax Providers" + * x-authenticated: true + * tags: + * - Store + * responses: + * 200: + * description: OK + * content: + * application/json: + * schema: + * properties: + * tax_providers: + * type: array + * items: + * $ref: "#/components/schemas/store" + */ +export default async (req, res) => { + const taxProviderService: TaxProviderService = + req.scope.resolve("taxProviderService") + const taxProviders = await taxProviderService.list() + res.status(200).json({ tax_providers: taxProviders }) +} diff --git a/packages/medusa/src/api/routes/admin/swaps/__tests__/get-swap.js b/packages/medusa/src/api/routes/admin/swaps/__tests__/get-swap.js index e1f0fb673d..168582678b 100644 --- a/packages/medusa/src/api/routes/admin/swaps/__tests__/get-swap.js +++ b/packages/medusa/src/api/routes/admin/swaps/__tests__/get-swap.js @@ -11,12 +11,6 @@ const defaultRelations = [ "shipping_address", "shipping_methods", "cart", - "cart.items", - "cart.region", - "cart.shipping_methods", - "cart.gift_cards", - "cart.discounts", - "cart.payment", ] const defaultFields = [ diff --git a/packages/medusa/src/api/routes/admin/swaps/index.ts b/packages/medusa/src/api/routes/admin/swaps/index.ts index 34aa1b140b..78fed60f0c 100644 --- a/packages/medusa/src/api/routes/admin/swaps/index.ts +++ b/packages/medusa/src/api/routes/admin/swaps/index.ts @@ -30,12 +30,6 @@ export const defaultAdminSwapRelations = [ "shipping_address", "shipping_methods", "cart", - "cart.items", - "cart.region", - "cart.shipping_methods", - "cart.gift_cards", - "cart.discounts", - "cart.payment", ] export const defaultAdminSwapFields = [ diff --git a/packages/medusa/src/api/routes/admin/tax-rates/add-to-product-types.ts b/packages/medusa/src/api/routes/admin/tax-rates/add-to-product-types.ts new file mode 100644 index 0000000000..d72844e40e --- /dev/null +++ b/packages/medusa/src/api/routes/admin/tax-rates/add-to-product-types.ts @@ -0,0 +1,66 @@ +import { pickByConfig, getRetrieveConfig } from "./utils/get-query-config" +import { IsArray, IsOptional } from "class-validator" + +import { TaxRate } from "../../../.." +import { TaxRateService } from "../../../../services" +import { validator } from "../../../../utils/validator" + +/** + * @oas [post] /tax-rates/:id/product-types/batch + * operationId: "PostTaxRatesTaxRateProductTypes" + * summary: "Add Tax Rate to Product Types" + * description: "Associates a Tax Rate with a list of Product Types" + * x-authenticated: true + * tags: + * - Tax Rates + * responses: + * 200: + * description: OK + * content: + * application/json: + * schema: + * properties: + * tax_rate: + * type: array + * items: + * $ref: "#/components/schemas/tax_rate" + */ +export default async (req, res) => { + const value = await validator( + AdminPostTaxRatesTaxRateProductTypesReq, + req.body + ) + + const query = await validator( + AdminPostTaxRatesTaxRateProductTypesParams, + req.query + ) + + const rateService: TaxRateService = req.scope.resolve("taxRateService") + + await rateService.addToProductType(req.params.id, value.product_types) + + const config = getRetrieveConfig( + query.fields as (keyof TaxRate)[], + query.expand + ) + const rate = await rateService.retrieve(req.params.id, config) + const data = pickByConfig(rate, config) + + res.json({ tax_rate: data }) +} + +export class AdminPostTaxRatesTaxRateProductTypesReq { + @IsArray() + product_types: string[] +} + +export class AdminPostTaxRatesTaxRateProductTypesParams { + @IsArray() + @IsOptional() + expand?: string[] + + @IsArray() + @IsOptional() + fields?: string[] +} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/add-to-products.ts b/packages/medusa/src/api/routes/admin/tax-rates/add-to-products.ts new file mode 100644 index 0000000000..2dfedb6235 --- /dev/null +++ b/packages/medusa/src/api/routes/admin/tax-rates/add-to-products.ts @@ -0,0 +1,63 @@ +import { pickByConfig, getRetrieveConfig } from "./utils/get-query-config" +import { IsArray, IsOptional } from "class-validator" + +import { TaxRate } from "../../../.." +import { TaxRateService } from "../../../../services" +import { validator } from "../../../../utils/validator" + +/** + * @oas [post] /tax-rates/:id/products/batch + * operationId: "PostTaxRatesTaxRateProducts" + * summary: "Add Tax Rate to Products" + * description: "Associates a Tax Rate with a list of Products" + * x-authenticated: true + * tags: + * - Tax Rates + * responses: + * 200: + * description: OK + * content: + * application/json: + * schema: + * properties: + * tax_rate: + * type: array + * items: + * $ref: "#/components/schemas/tax_rate" + */ +export default async (req, res) => { + const value = await validator(AdminPostTaxRatesTaxRateProductsReq, req.body) + + const query = await validator( + AdminPostTaxRatesTaxRateProductsParams, + req.query + ) + + const rateService: TaxRateService = req.scope.resolve("taxRateService") + + await rateService.addToProduct(req.params.id, value.products) + + const config = getRetrieveConfig( + query.fields as (keyof TaxRate)[], + query.expand + ) + const rate = await rateService.retrieve(req.params.id, config) + const data = pickByConfig(rate, config) + + res.json({ tax_rate: data }) +} + +export class AdminPostTaxRatesTaxRateProductsReq { + @IsArray() + products: string[] +} + +export class AdminPostTaxRatesTaxRateProductsParams { + @IsArray() + @IsOptional() + expand?: string[] + + @IsArray() + @IsOptional() + fields?: string[] +} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/add-to-shipping-options.ts b/packages/medusa/src/api/routes/admin/tax-rates/add-to-shipping-options.ts new file mode 100644 index 0000000000..985f9f143c --- /dev/null +++ b/packages/medusa/src/api/routes/admin/tax-rates/add-to-shipping-options.ts @@ -0,0 +1,65 @@ +import { pickByConfig, getRetrieveConfig } from "./utils/get-query-config" +import { IsArray, IsOptional } from "class-validator" + +import { TaxRate } from "../../../.." +import { TaxRateService } from "../../../../services" +import { validator } from "../../../../utils/validator" + +/** + * @oas [post] /tax-rates/:id/shipping-options/batch + * operationId: "PostTaxRatesTaxRateShippingOptions" + * summary: "Add Tax Rate to Product Types" + * description: "Associates a Tax Rate with a list of Product Types" + * x-authenticated: true + * tags: + * - Tax Rates + * responses: + * 200: + * description: OK + * content: + * application/json: + * schema: + * properties: + * tax_rate: + * type: array + * items: + * $ref: "#/components/schemas/tax_rate" + */ +export default async (req, res) => { + const value = await validator( + AdminPostTaxRatesTaxRateShippingOptionsReq, + req.body + ) + + const query = await validator( + AdminPostTaxRatesTaxRateShippingOptionsParams, + req.query + ) + + const rateService: TaxRateService = req.scope.resolve("taxRateService") + await rateService.addToShippingOption(req.params.id, value.shipping_options) + + const config = getRetrieveConfig( + query.fields as (keyof TaxRate)[], + query.expand + ) + const rate = await rateService.retrieve(req.params.id, config) + const data = pickByConfig(rate, config) + + res.json({ tax_rate: data }) +} + +export class AdminPostTaxRatesTaxRateShippingOptionsReq { + @IsArray() + shipping_options: string[] +} + +export class AdminPostTaxRatesTaxRateShippingOptionsParams { + @IsArray() + @IsOptional() + expand?: string[] + + @IsArray() + @IsOptional() + fields?: string[] +} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/create-tax-rate.ts b/packages/medusa/src/api/routes/admin/tax-rates/create-tax-rate.ts new file mode 100644 index 0000000000..a341d64139 --- /dev/null +++ b/packages/medusa/src/api/routes/admin/tax-rates/create-tax-rate.ts @@ -0,0 +1,114 @@ +import { EntityManager } from "typeorm" +import { IsString, IsArray, IsOptional } from "class-validator" +import { omit } from "lodash" +import { MedusaError } from "medusa-core-utils" + +import { pickByConfig, getRetrieveConfig } from "./utils/get-query-config" +import { TaxRate } from "../../../.." +import { TaxRateService } from "../../../../services" +import { validator } from "../../../../utils/validator" +import { IsType } from "../../../../utils/validators/is-type" + +/** + * @oas [post] /tax-rates + * operationId: "PostTaxRates" + * summary: "Create a Tax Rate" + * description: "Creates a Tax Rate" + * x-authenticated: true + * tags: + * - Tax Rates + * responses: + * 200: + * description: OK + * content: + * application/json: + * schema: + * properties: + * tax_rate: + * type: array + * items: + * $ref: "#/components/schemas/tax_rate" + */ +export default async (req, res) => { + const value = await validator(AdminPostTaxRatesReq, req.body) + + const query = await validator(AdminPostTaxRatesParams, req.query) + + const manager: EntityManager = req.scope.resolve("manager") + const rateService: TaxRateService = req.scope.resolve("taxRateService") + + let id: string | undefined + await manager.transaction(async (tx) => { + const txRateService = rateService.withTransaction(tx) + const created = await txRateService.create( + omit(value, ["products", "product_types", "shipping_options"]) + ) + id = created.id + + if (typeof value.products !== "undefined") { + await txRateService.addToProduct(id, value.products) + } + + if (typeof value.product_types !== "undefined") { + await txRateService.addToProductType(id, value.product_types) + } + + if (typeof value.shipping_options !== "undefined") { + await txRateService.addToShippingOption(id, value.shipping_options) + } + }) + + if (typeof id === "undefined") { + throw new MedusaError( + MedusaError.Types.UNEXPECTED_STATE, + "Tax Rate was not created" + ) + } + + const config = getRetrieveConfig( + query.fields as (keyof TaxRate)[], + query.expand + ) + + const rate = await rateService.retrieve(id, config) + const data = pickByConfig(rate, config) + + res.json({ tax_rate: data }) +} + +export class AdminPostTaxRatesReq { + @IsString() + code: string + + @IsString() + name: string + + @IsString() + region_id: string + + @IsOptional() + @IsType([Number, null]) + rate?: number | null + + @IsOptional() + @IsArray() + products?: string[] + + @IsOptional() + @IsArray() + shipping_options?: string[] + + @IsOptional() + @IsArray() + product_types?: string[] +} + +export class AdminPostTaxRatesParams { + @IsArray() + @IsOptional() + expand?: string[] + + @IsArray() + @IsOptional() + fields?: string[] +} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/delete-tax-rate.ts b/packages/medusa/src/api/routes/admin/tax-rates/delete-tax-rate.ts new file mode 100644 index 0000000000..129c0f3614 --- /dev/null +++ b/packages/medusa/src/api/routes/admin/tax-rates/delete-tax-rate.ts @@ -0,0 +1,40 @@ +import { TaxRateService } from "../../../../services" + +/** + * @oas [delete] /tax-rates/{id} + * operationId: "DeleteTaxRatesTaxRate" + * summary: "Delete a Tax Rate" + * description: "Deletes a Tax Rate" + * x-authenticated: true + * parameters: + * - (path) id=* {string} The id of the Shipping Option. + * tags: + * - Tax Rates + * responses: + * 200: + * description: OK + * content: + * application/json: + * schema: + * properties: + * id: + * type: string + * description: The id of the deleted Shipping Option. + * object: + * type: string + * description: The type of the object that was deleted. + * deleted: + * type: boolean + */ +export default async (req, res) => { + const { id } = req.params + const taxRateService: TaxRateService = req.scope.resolve("taxRateService") + + await taxRateService.delete(id) + + res.json({ + id: id, + object: "tax-rate", + deleted: true, + }) +} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/get-tax-rate.ts b/packages/medusa/src/api/routes/admin/tax-rates/get-tax-rate.ts new file mode 100644 index 0000000000..f5b8928b08 --- /dev/null +++ b/packages/medusa/src/api/routes/admin/tax-rates/get-tax-rate.ts @@ -0,0 +1,50 @@ +import { getRetrieveConfig, pickByConfig } from "./utils/get-query-config" +import { IsArray, IsOptional } from "class-validator" + +import { TaxRate } from "../../../.." +import { TaxRateService } from "../../../../services" +import { validator } from "../../../../utils/validator" + +/** + * @oas [get] /tax-rates/:id + * operationId: "GetTaxRatesTaxRate" + * summary: "Get Tax Rate" + * description: "Retrieves a TaxRate" + * x-authenticated: true + * tags: + * - Tax Rates + * responses: + * 200: + * description: OK + * content: + * application/json: + * schema: + * properties: + * tax_rate: + * type: array + * items: + * $ref: "#/components/schemas/tax_rate" + */ +export default async (req, res) => { + const value = await validator(AdminGetTaxRatesTaxRateParams, req.query) + + const rateService: TaxRateService = req.scope.resolve("taxRateService") + const config = getRetrieveConfig( + value.fields as (keyof TaxRate)[], + value.expand + ) + const rate = await rateService.retrieve(req.params.id, config) + const data = pickByConfig(rate, config) + + res.json({ tax_rate: data }) +} + +export class AdminGetTaxRatesTaxRateParams { + @IsArray() + @IsOptional() + expand?: string[] + + @IsArray() + @IsOptional() + fields?: string[] +} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/index.ts b/packages/medusa/src/api/routes/admin/tax-rates/index.ts new file mode 100644 index 0000000000..10fac4404c --- /dev/null +++ b/packages/medusa/src/api/routes/admin/tax-rates/index.ts @@ -0,0 +1,119 @@ +import { Router } from "express" +import { TaxRate } from "../../../.." +import { DeleteResponse, PaginatedResponse } from "../../../../types/common" +import middlewares from "../../../middlewares" + +const route = Router() + +export default (app) => { + app.use("/tax-rates", route) + + /** + * List tax rates + */ + route.get("/", middlewares.wrap(require("./list-tax-rates").default)) + + /** + * Get a tax rate + */ + route.get("/:id", middlewares.wrap(require("./get-tax-rate").default)) + + /** + * Create a tax rate + */ + route.post("/", middlewares.wrap(require("./create-tax-rate").default)) + + /** + * Update a tax rate + */ + route.post("/:id", middlewares.wrap(require("./update-tax-rate").default)) + + /** + * Remove products from tax rate + */ + route.delete( + "/:id/products/batch", + middlewares.wrap(require("./remove-from-products").default) + ) + + /** + * Remove product types from tax rate + */ + route.delete( + "/:id/product-types/batch", + middlewares.wrap(require("./remove-from-product-types").default) + ) + + /** + * Remove shipping options from tax rate + */ + route.delete( + "/:id/shipping-options/batch", + middlewares.wrap(require("./remove-from-shipping-options").default) + ) + + /** + * Add products to tax rate + */ + route.post( + "/:id/products/batch", + middlewares.wrap(require("./add-to-products").default) + ) + + /** + * Add product types to tax rate + */ + route.post( + "/:id/product-types/batch", + middlewares.wrap(require("./add-to-product-types").default) + ) + + /** + * Add to shipping options + */ + route.post( + "/:id/shipping-options/batch", + middlewares.wrap(require("./add-to-shipping-options").default) + ) + + /** + * Delete a tax rate + */ + route.delete("/:id", middlewares.wrap(require("./delete-tax-rate").default)) + + return app +} + +export const defaultAdminTaxRatesRelations = [] + +export const defaultAdminTaxRatesFields: (keyof TaxRate)[] = [ + "id", + "rate", + "code", + "name", + "region_id", + "created_at", + "updated_at", +] + +export type AdminTaxRatesDeleteRes = DeleteResponse + +export type AdminTaxRatesListRes = PaginatedResponse & { + tax_rates: TaxRate[] +} + +export type AdminTaxRatesRes = { + tax_rate: TaxRate +} + +export * from "./list-tax-rates" +export * from "./get-tax-rate" +export * from "./remove-from-product-types" +export * from "./remove-from-products" +export * from "./remove-from-shipping-options" +export * from "./add-to-product-types" +export * from "./add-to-products" +export * from "./add-to-shipping-options" +export * from "./create-tax-rate" +export * from "./delete-tax-rate" +export * from "./update-tax-rate" diff --git a/packages/medusa/src/api/routes/admin/tax-rates/list-tax-rates.ts b/packages/medusa/src/api/routes/admin/tax-rates/list-tax-rates.ts new file mode 100644 index 0000000000..5c1e6069d2 --- /dev/null +++ b/packages/medusa/src/api/routes/admin/tax-rates/list-tax-rates.ts @@ -0,0 +1,111 @@ +import { getListConfig, pickByConfig } from "./utils/get-query-config" +import { + IsArray, + ValidateNested, + IsNumber, + IsOptional, + IsString, +} from "class-validator" +import { Type } from "class-transformer" +import { omit, pickBy, pick, identity } from "lodash" + +import { TaxRate } from "../../../.." +import { + NumericalComparisonOperator, + FindConfig, +} from "../../../../types/common" +import { TaxRateService } from "../../../../services" +import { IsType } from "../../../../utils/validators/is-type" +import { validator } from "../../../../utils/validator" + +/** + * @oas [get] /tax-rates + * operationId: "GetTaxRates" + * summary: "List Tax Rates" + * description: "Retrieves a list of TaxRates" + * x-authenticated: true + * parameters: + * - (query) q {string} Query used for searching orders. + * - (query) id {string} Id of the order to search for. + * - (query) region_id {string} to search for. + * - (query) code {string} to search for. + * - (query) rate {string} to search for. + * - (query) created_at {DateComparisonOperator} Date comparison for when resulting orders was created, i.e. less than, greater than etc. + * - (query) updated_at {DateComparisonOperator} Date comparison for when resulting orders was updated, i.e. less than, greater than etc. + * - (query) offset {string} How many orders to skip in the result. + * - (query) limit {string} Limit the number of orders returned. + * - (query) fields {string} (Comma separated) Which fields should be included in each order of the result. + * tags: + * - Order + * responses: + * 200: + * description: OK + * content: + * application/json: + * schema: + * properties: + * orders: + * type: array + * items: + * $ref: "#/components/schemas/order" + */ +export default async (req, res) => { + const value = await validator(AdminGetTaxRatesParams, req.query) + + const rateService: TaxRateService = req.scope.resolve("taxRateService") + + const listConfig = getListConfig() + + const filterableFields = omit(value, [ + "limit", + "offset", + "expand", + "fields", + "order", + ]) + + const [rates, count] = await rateService.listAndCount( + pickBy(filterableFields, identity), + listConfig + ) + + const data = pickByConfig(rates, listConfig) + + res.json({ tax_rates: data, count, offset: value.offset, limit: value.limit }) +} + +export class AdminGetTaxRatesParams { + @IsOptional() + @IsType([String, [String]]) + region_id?: string | string[] + + @IsString() + @IsOptional() + name?: string + + @IsString() + @IsOptional() + code?: string + + @IsType([NumericalComparisonOperator, Number]) + @IsOptional() + rate?: number | NumericalComparisonOperator + + @IsNumber() + @IsOptional() + @Type(() => Number) + offset? = 0 + + @IsNumber() + @IsOptional() + @Type(() => Number) + limit? = 50 + + @IsArray() + @IsOptional() + expand?: string[] + + @IsArray() + @IsOptional() + fields?: string[] +} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/remove-from-product-types.ts b/packages/medusa/src/api/routes/admin/tax-rates/remove-from-product-types.ts new file mode 100644 index 0000000000..ffeb1e858d --- /dev/null +++ b/packages/medusa/src/api/routes/admin/tax-rates/remove-from-product-types.ts @@ -0,0 +1,66 @@ +import { pickByConfig, getRetrieveConfig } from "./utils/get-query-config" +import { IsArray, IsOptional } from "class-validator" + +import { TaxRate } from "../../../.." +import { TaxRateService } from "../../../../services" +import { validator } from "../../../../utils/validator" + +/** + * @oas [delete] /tax-rates/:id/product-types/batch + * operationId: "DeleteTaxRatesTaxRateProductTypes" + * summary: "Remove Tax Rate from Product Types" + * description: "Removes a Tax Rate from a list of Product Types" + * x-authenticated: true + * tags: + * - Tax Rates + * responses: + * 200: + * description: OK + * content: + * application/json: + * schema: + * properties: + * tax_rate: + * type: array + * items: + * $ref: "#/components/schemas/tax_rate" + */ +export default async (req, res) => { + const value = await validator( + AdminDeleteTaxRatesTaxRateProductTypesReq, + req.body + ) + + const query = await validator( + AdminDeleteTaxRatesTaxRateProductTypesParams, + req.query + ) + + const rateService: TaxRateService = req.scope.resolve("taxRateService") + + await rateService.removeFromProductType(req.params.id, value.product_types) + + const config = getRetrieveConfig( + query.fields as (keyof TaxRate)[], + query.expand + ) + const rate = await rateService.retrieve(req.params.id, config) + const data = pickByConfig(rate, config) + + res.json({ tax_rate: data }) +} + +export class AdminDeleteTaxRatesTaxRateProductTypesReq { + @IsArray() + product_types: string[] +} + +export class AdminDeleteTaxRatesTaxRateProductTypesParams { + @IsArray() + @IsOptional() + expand?: string[] + + @IsArray() + @IsOptional() + fields?: string[] +} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/remove-from-products.ts b/packages/medusa/src/api/routes/admin/tax-rates/remove-from-products.ts new file mode 100644 index 0000000000..4727e93fbb --- /dev/null +++ b/packages/medusa/src/api/routes/admin/tax-rates/remove-from-products.ts @@ -0,0 +1,63 @@ +import { pickByConfig, getRetrieveConfig } from "./utils/get-query-config" +import { IsArray, IsOptional } from "class-validator" + +import { TaxRate } from "../../../.." +import { TaxRateService } from "../../../../services" +import { validator } from "../../../../utils/validator" + +/** + * @oas [delete] /tax-rates/:id/products/batch + * operationId: "DeleteTaxRatesTaxRateProducts" + * summary: "Removes Tax Rate from Products" + * description: "Removes a Tax Rate from a list of Products" + * x-authenticated: true + * tags: + * - Tax Rates + * responses: + * 200: + * description: OK + * content: + * application/json: + * schema: + * properties: + * tax_rate: + * type: array + * items: + * $ref: "#/components/schemas/tax_rate" + */ +export default async (req, res) => { + const value = await validator(AdminDeleteTaxRatesTaxRateProductsReq, req.body) + + const query = await validator( + AdminDeleteTaxRatesTaxRateProductsParams, + req.query + ) + + const rateService: TaxRateService = req.scope.resolve("taxRateService") + + await rateService.removeFromProduct(req.params.id, value.products) + + const config = getRetrieveConfig( + query.fields as (keyof TaxRate)[], + query.expand + ) + const rate = await rateService.retrieve(req.params.id, config) + const data = pickByConfig(rate, config) + + res.json({ tax_rate: data }) +} + +export class AdminDeleteTaxRatesTaxRateProductsReq { + @IsArray() + products: string[] +} + +export class AdminDeleteTaxRatesTaxRateProductsParams { + @IsArray() + @IsOptional() + expand?: string[] + + @IsArray() + @IsOptional() + fields?: string[] +} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/remove-from-shipping-options.ts b/packages/medusa/src/api/routes/admin/tax-rates/remove-from-shipping-options.ts new file mode 100644 index 0000000000..1e2bd9b823 --- /dev/null +++ b/packages/medusa/src/api/routes/admin/tax-rates/remove-from-shipping-options.ts @@ -0,0 +1,69 @@ +import { pickByConfig, getRetrieveConfig } from "./utils/get-query-config" +import { IsArray, IsOptional } from "class-validator" + +import { TaxRate } from "../../../.." +import { TaxRateService } from "../../../../services" +import { validator } from "../../../../utils/validator" + +/** + * @oas [delete] /tax-rates/:id/shipping-options/batch + * operationId: "DeleteTaxRatesTaxRateShippingOptions" + * summary: "Removes a Tax Rate from Product Types" + * description: "Removes a Tax Rate from a list of Product Types" + * x-authenticated: true + * tags: + * - Tax Rates + * responses: + * 200: + * description: OK + * content: + * application/json: + * schema: + * properties: + * tax_rate: + * type: array + * items: + * $ref: "#/components/schemas/tax_rate" + */ +export default async (req, res) => { + const value = await validator( + AdminDeleteTaxRatesTaxRateShippingOptionsReq, + req.body + ) + + const query = await validator( + AdminDeleteTaxRatesTaxRateShippingOptionsParams, + req.query + ) + + const rateService: TaxRateService = req.scope.resolve("taxRateService") + + await rateService.removeFromShippingOption( + req.params.id, + value.shipping_options + ) + + const config = getRetrieveConfig( + query.fields as (keyof TaxRate)[], + query.expand + ) + const rate = await rateService.retrieve(req.params.id, config) + const data = pickByConfig(rate, config) + + res.json({ tax_rate: data }) +} + +export class AdminDeleteTaxRatesTaxRateShippingOptionsReq { + @IsArray() + shipping_options: string[] +} + +export class AdminDeleteTaxRatesTaxRateShippingOptionsParams { + @IsArray() + @IsOptional() + expand?: string[] + + @IsArray() + @IsOptional() + fields?: string[] +} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/update-tax-rate.ts b/packages/medusa/src/api/routes/admin/tax-rates/update-tax-rate.ts new file mode 100644 index 0000000000..3930afc311 --- /dev/null +++ b/packages/medusa/src/api/routes/admin/tax-rates/update-tax-rate.ts @@ -0,0 +1,116 @@ +import { EntityManager } from "typeorm" +import { IsString, IsArray, IsOptional } from "class-validator" +import { omit } from "lodash" + +import { pickByConfig, getRetrieveConfig } from "./utils/get-query-config" +import { TaxRate } from "../../../.." +import { TaxRateService } from "../../../../services" +import { validator } from "../../../../utils/validator" +import { IsType } from "../../../../utils/validators/is-type" + +/** + * @oas [post] /tax-rates/:id + * operationId: "PostTaxRatesTaxRate" + * summary: "Update a Tax Rate" + * description: "Updates a Tax Rate" + * x-authenticated: true + * tags: + * - Tax Rates + * responses: + * 200: + * description: OK + * content: + * application/json: + * schema: + * properties: + * tax_rate: + * type: array + * items: + * $ref: "#/components/schemas/tax_rate" + */ +export default async (req, res) => { + const value = await validator(AdminPostTaxRatesTaxRateReq, req.body) + + const query = await validator(AdminPostTaxRatesTaxRateParams, req.query) + + const manager: EntityManager = req.scope.resolve("manager") + const rateService: TaxRateService = req.scope.resolve("taxRateService") + + await manager.transaction(async (tx) => { + const txRateService = rateService.withTransaction(tx) + await txRateService.update( + req.params.id, + omit(value, ["products", "product_types", "shipping_options"]) + ) + + if (typeof value.products !== "undefined") { + await txRateService.addToProduct(req.params.id, value.products, true) + } + + if (typeof value.product_types !== "undefined") { + await txRateService.addToProductType( + req.params.id, + value.product_types, + true + ) + } + + if (typeof value.shipping_options !== "undefined") { + await txRateService.addToShippingOption( + req.params.id, + value.shipping_options, + true + ) + } + }) + + const config = getRetrieveConfig( + query.fields as (keyof TaxRate)[], + query.expand + ) + + const rate = await rateService.retrieve(req.params.id, config) + const data = pickByConfig(rate, config) + + res.json({ tax_rate: data }) +} + +export class AdminPostTaxRatesTaxRateReq { + @IsOptional() + @IsString() + code?: string + + @IsOptional() + @IsString() + name?: string + + @IsOptional() + @IsString() + region_id?: string + + @IsOptional() + @IsType([Number, null]) + rate?: number | null + + @IsOptional() + @IsArray() + products?: string[] + + @IsOptional() + @IsArray() + shipping_options?: string[] + + @IsOptional() + @IsArray() + product_types?: string[] +} + +export class AdminPostTaxRatesTaxRateParams { + @IsArray() + @IsOptional() + expand?: string[] + + @IsArray() + @IsOptional() + fields?: string[] +} diff --git a/packages/medusa/src/api/routes/admin/tax-rates/utils/get-query-config.ts b/packages/medusa/src/api/routes/admin/tax-rates/utils/get-query-config.ts new file mode 100644 index 0000000000..a8ce900e82 --- /dev/null +++ b/packages/medusa/src/api/routes/admin/tax-rates/utils/get-query-config.ts @@ -0,0 +1,78 @@ +import { defaultAdminTaxRatesFields, defaultAdminTaxRatesRelations } from "../" +import { pick } from "lodash" +import { FindConfig } from "../../../../../types/common" +import { TaxRate } from "../../../../.." + +export function pickByConfig( + obj: T | T[], + config: FindConfig +): Partial | Partial[] { + const fields = [...(config.select ?? []), ...(config.relations ?? [])] + + if (fields.length) { + if (Array.isArray(obj)) { + return obj.map((o) => pick(o, fields)) + } else { + return pick(obj, fields) + } + } + return obj +} + +export function getRetrieveConfig( + fields?: (keyof TaxRate)[], + expand?: string[] +): FindConfig { + let includeFields: (keyof TaxRate)[] = [] + if (typeof fields !== "undefined") { + const fieldSet = new Set(fields) + fieldSet.add("id") + includeFields = Array.from(fieldSet) as (keyof TaxRate)[] + } + + let expandFields: string[] = [] + if (typeof expand !== "undefined") { + expandFields = expand + } + + return { + select: includeFields.length ? includeFields : defaultAdminTaxRatesFields, + relations: expandFields.length + ? expandFields + : defaultAdminTaxRatesRelations, + } +} + +export function getListConfig( + fields?: (keyof TaxRate)[], + expand?: string[], + limit = 50, + offset = 0, + order?: { [k: symbol]: "DESC" | "ASC" } +): FindConfig { + let includeFields: (keyof TaxRate)[] = [] + if (typeof fields !== "undefined") { + const fieldSet = new Set(fields) + // Ensure created_at is included, since we are sorting on this + fieldSet.add("created_at") + fieldSet.add("id") + includeFields = Array.from(fieldSet) as (keyof TaxRate)[] + } + + let expandFields: string[] = [] + if (typeof expand !== "undefined") { + expandFields = expand + } + + const orderBy = order ?? { created_at: "DESC" } + + return { + select: includeFields.length ? includeFields : defaultAdminTaxRatesFields, + relations: expandFields.length + ? expandFields + : defaultAdminTaxRatesRelations, + skip: offset, + take: limit, + order: orderBy, + } +} diff --git a/packages/medusa/src/api/routes/store/carts/__tests__/complete-cart.js b/packages/medusa/src/api/routes/store/carts/__tests__/complete-cart.js index b19a7ba7fc..db57d0a320 100644 --- a/packages/medusa/src/api/routes/store/carts/__tests__/complete-cart.js +++ b/packages/medusa/src/api/routes/store/carts/__tests__/complete-cart.js @@ -1,119 +1,56 @@ -import { IdMap } from "medusa-test-utils" import { request } from "../../../../../helpers/test-request" -import { CartServiceMock } from "../../../../../services/__mocks__/cart" -import { OrderServiceMock } from "../../../../../services/__mocks__/order" -import { SwapServiceMock } from "../../../../../services/__mocks__/swap" +import { CompletionStrategyMock } from "../../../../../strategies/__mocks__/cart-completion" -describe("POST /store/carts/:id", () => { - describe("successfully completes a normal cart", () => { +describe("POST /store/carts/:id/complete", () => { + describe("successfully calls completion strategy - Legacy Endpoint", () => { let subject beforeAll(async () => { - subject = await request( - "POST", - `/store/carts/${IdMap.getId("test-cart")}/complete-cart` - ) + subject = await request("POST", `/store/carts/test-cart/complete-cart`) }) afterAll(() => { jest.clearAllMocks() }) - it("Call CartService authorizePayment", () => { - expect(CartServiceMock.authorizePayment).toHaveBeenCalledTimes(1) - expect(CartServiceMock.authorizePayment).toHaveBeenCalledWith( - IdMap.getId("test-cart"), - { idempotency_key: "testkey" } + it("calls completion strat", () => { + expect(CompletionStrategyMock.complete).toHaveBeenCalledTimes(1) + expect(CompletionStrategyMock.complete).toHaveBeenCalledWith( + "test-cart", + { idempotency_key: "testkey", recovery_point: "started" }, + undefined ) }) - it("Call OrderService createFromCart", () => { - expect(OrderServiceMock.createFromCart).toHaveBeenCalledTimes(1) - expect(OrderServiceMock.createFromCart).toHaveBeenCalledWith( - IdMap.getId("test-cart") - ) - }) - - it("returns 200", () => { + it("responds correctly", () => { expect(subject.status).toEqual(200) - }) - - it("returns the created order", () => { - expect(subject.body.data.id).toEqual(IdMap.getId("test-order")) + expect(subject.body).toEqual({}) }) }) - describe("successfully completes a swap cart", () => { + describe("successfully calls completion strategy", () => { let subject beforeAll(async () => { - subject = await request( - "POST", - `/store/carts/${IdMap.getId("swap-cart")}/complete-cart` - ) + subject = await request("POST", `/store/carts/test-cart/complete`) }) afterAll(() => { jest.clearAllMocks() }) - it("Call CartService authorizePayment", () => { - expect(CartServiceMock.authorizePayment).toHaveBeenCalledTimes(1) - expect(CartServiceMock.authorizePayment).toHaveBeenCalledWith( - IdMap.getId("swap-cart"), - { idempotency_key: "testkey" } + it("calls completion strat", () => { + expect(CompletionStrategyMock.complete).toHaveBeenCalledTimes(1) + expect(CompletionStrategyMock.complete).toHaveBeenCalledWith( + "test-cart", + { idempotency_key: "testkey", recovery_point: "started" }, + undefined ) }) - it("Call SwapService registerCartCompletion", () => { - expect(SwapServiceMock.registerCartCompletion).toHaveBeenCalledTimes(1) - expect(SwapServiceMock.registerCartCompletion).toHaveBeenCalledWith( - "test-swap" - ) - }) - - it("returns 200", () => { + it("responds correctly", () => { expect(subject.status).toEqual(200) - }) - - it("returns the created order", () => { - expect(subject.body.data.id).toEqual("test-swap") - }) - }) - - describe("returns early if payment requires more work", () => { - let subject - - beforeAll(async () => { - subject = await request( - "POST", - `/store/carts/${IdMap.getId("test-cart2")}/complete-cart` - ) - }) - - afterAll(() => { - jest.clearAllMocks() - }) - - it("Call CartService authorizePayment", () => { - expect(CartServiceMock.authorizePayment).toHaveBeenCalledTimes(1) - expect(CartServiceMock.authorizePayment).toHaveBeenCalledWith( - IdMap.getId("test-cart2"), - { idempotency_key: "testkey" } - ) - }) - - it("Call CartService retrieve 1 time", () => { - expect(CartServiceMock.retrieve).toHaveBeenCalledTimes(1) - }) - - it("returns 200", () => { - expect(subject.status).toEqual(200) - }) - - it("returns the created order", () => { - expect(subject.body.data.id).toEqual(IdMap.getId("test-cart2")) - expect(subject.body.data.payment_session.status).toEqual("requires_more") + expect(subject.body).toEqual({}) }) }) }) diff --git a/packages/medusa/src/api/routes/store/carts/calculate-taxes.ts b/packages/medusa/src/api/routes/store/carts/calculate-taxes.ts new file mode 100644 index 0000000000..ed055e1648 --- /dev/null +++ b/packages/medusa/src/api/routes/store/carts/calculate-taxes.ts @@ -0,0 +1,118 @@ +import { EntityManager } from "typeorm" +import { IdempotencyKey } from "../../../../models/idempotency-key" +import { CartService, IdempotencyKeyService } from "../../../../services" + +/** + * @oas [post] /carts/{id}/taxes + * summary: "Calculate Cart Taxes" + * operationId: "PostCartsCartTaxes" + * description: "Calculates taxes for a cart. Depending on the cart's region + * this may involve making 3rd party API calls to a Tax Provider service." + * parameters: + * - (path) id=* {String} The Cart id. + * tags: + * - Cart + * responses: + * 200: + * description: "A cart object with the tax_total field populated" + * content: + * application/json: + * schema: + * oneOf: + * - type: object + * properties: + * cart: + * $ref: "#/components/schemas/cart" + */ +export default async (req, res) => { + const { id } = req.params + + const idempotencyKeyService: IdempotencyKeyService = req.scope.resolve( + "idempotencyKeyService" + ) + + const headerKey = req.get("Idempotency-Key") || "" + + let idempotencyKey: IdempotencyKey + try { + idempotencyKey = await idempotencyKeyService.initializeRequest( + headerKey, + req.method, + req.params, + req.path + ) + } catch (error) { + console.log(error) + res.status(409).send("Failed to create idempotency key") + return + } + + res.setHeader("Access-Control-Expose-Headers", "Idempotency-Key") + res.setHeader("Idempotency-Key", idempotencyKey.idempotency_key) + + const cartService: CartService = req.scope.resolve("cartService") + + let inProgress = true + let err = false + + while (inProgress) { + switch (idempotencyKey.recovery_point) { + case "started": { + const { key, error } = await idempotencyKeyService.workStage( + idempotencyKey.idempotency_key, + async (manager: EntityManager) => { + const cart = await cartService.withTransaction(manager).retrieve( + id, + { + select: [ + "total", + "subtotal", + "tax_total", + "discount_total", + "shipping_total", + "gift_card_total", + ], + }, + { force_taxes: true } + ) + + return { + response_code: 200, + response_body: { cart }, + } + } + ) + + if (error) { + inProgress = false + err = error + } else { + idempotencyKey = key + } + break + } + + case "finished": { + inProgress = false + break + } + + default: + idempotencyKey = await idempotencyKeyService.update( + idempotencyKey.idempotency_key, + { + recovery_point: "finished", + response_code: 500, + response_body: { message: "Unknown recovery point" }, + } + ) + break + } + } + + if (err) { + throw err + } + + res.status(idempotencyKey.response_code).json(idempotencyKey.response_body) +} diff --git a/packages/medusa/src/api/routes/store/carts/complete-cart.ts b/packages/medusa/src/api/routes/store/carts/complete-cart.ts index f7f5bf2c2b..bcf018aca6 100644 --- a/packages/medusa/src/api/routes/store/carts/complete-cart.ts +++ b/packages/medusa/src/api/routes/store/carts/complete-cart.ts @@ -1,12 +1,6 @@ -import { MedusaError } from "medusa-core-utils" -import { - CartService, - IdempotencyKeyService, - OrderService, - SwapService, -} from "../../../../services" - -import { Order } from "../../../../models/order" +import { ICartCompletionStrategy } from "../../../../interfaces" +import { IdempotencyKeyService } from "../../../../services" +import { IdempotencyKey } from "../../../../models/idempotency-key" /** * @oas [post] /carts/{id}/complete @@ -54,7 +48,7 @@ export default async (req, res) => { const headerKey = req.get("Idempotency-Key") || "" - let idempotencyKey + let idempotencyKey: IdempotencyKey try { idempotencyKey = await idempotencyKeyService.initializeRequest( headerKey, @@ -71,231 +65,15 @@ export default async (req, res) => { res.setHeader("Access-Control-Expose-Headers", "Idempotency-Key") res.setHeader("Idempotency-Key", idempotencyKey.idempotency_key) - const cartService: CartService = req.scope.resolve("cartService") - const orderService: OrderService = req.scope.resolve("orderService") - const swapService: SwapService = req.scope.resolve("swapService") + const completionStrat: ICartCompletionStrategy = req.scope.resolve( + "cartCompletionStrategy" + ) - let inProgress = true - let err = false + const { response_code, response_body } = await completionStrat.complete( + id, + idempotencyKey, + req.request_context + ) - while (inProgress) { - switch (idempotencyKey.recovery_point) { - case "started": { - const { key, error } = await idempotencyKeyService.workStage( - idempotencyKey.idempotency_key, - async (manager) => { - let cart = await cartService.withTransaction(manager).retrieve(id) - - if (cart.completed_at) { - return { - response_code: 409, - response_body: { - code: MedusaError.Codes.CART_INCOMPATIBLE_STATE, - message: "Cart has already been completed", - type: MedusaError.Types.NOT_ALLOWED, - }, - } - } - - cart = await cartService - .withTransaction(manager) - .authorizePayment(id, { - ...req.request_context, - idempotency_key: idempotencyKey.idempotency_key, - }) - - if (cart.payment_session) { - if ( - cart.payment_session.status === "requires_more" || - cart.payment_session.status === "pending" - ) { - return { - response_code: 200, - response_body: { - data: cart, - payment_status: cart.payment_session.status, - type: "cart", - }, - } - } - } - - return { - recovery_point: "payment_authorized", - } - } - ) - - if (error) { - inProgress = false - err = error - } else { - idempotencyKey = key - } - break - } - - case "payment_authorized": { - const { key, error } = await idempotencyKeyService.workStage( - idempotencyKey.idempotency_key, - async (manager) => { - const cart = await cartService - .withTransaction(manager) - .retrieve(id, { - select: ["total"], - relations: ["payment", "payment_sessions"], - }) - - let order: Order - - // If cart is part of swap, we register swap as complete - switch (cart.type) { - case "swap": { - try { - const swapId = cart.metadata?.swap_id - let swap = await swapService - .withTransaction(manager) - .registerCartCompletion(swapId) - - swap = await swapService - .withTransaction(manager) - .retrieve(swap.id, { relations: ["shipping_address"] }) - - return { - response_code: 200, - response_body: { data: swap, type: "swap" }, - } - } catch (error) { - if ( - error && - error.code === MedusaError.Codes.INSUFFICIENT_INVENTORY - ) { - return { - response_code: 409, - response_body: { - message: error.message, - type: error.type, - code: error.code, - }, - } - } else { - throw error - } - } - } - // case "payment_link": - default: { - if (typeof cart.total === "undefined") { - return { - response_code: 500, - response_body: { - message: "Unexpected state", - }, - } - } - - if (!cart.payment && cart.total > 0) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - `Cart payment not authorized` - ) - } - - try { - order = await orderService - .withTransaction(manager) - .createFromCart(cart.id) - } catch (error) { - if ( - error && - error.message === "Order from cart already exists" - ) { - order = await orderService - .withTransaction(manager) - .retrieveByCartId(id, { - select: [ - "subtotal", - "tax_total", - "shipping_total", - "discount_total", - "total", - ], - relations: ["shipping_address", "items", "payments"], - }) - - return { - response_code: 200, - response_body: { data: order, type: "order" }, - } - } else if ( - error && - error.code === MedusaError.Codes.INSUFFICIENT_INVENTORY - ) { - return { - response_code: 409, - response_body: { - message: error.message, - type: error.type, - code: error.code, - }, - } - } else { - throw error - } - } - } - } - - order = await orderService - .withTransaction(manager) - .retrieve(order.id, { - select: [ - "subtotal", - "tax_total", - "shipping_total", - "discount_total", - "total", - ], - relations: ["shipping_address", "items", "payments"], - }) - - return { - response_code: 200, - response_body: { data: order, type: "order" }, - } - } - ) - - if (error) { - inProgress = false - err = error - } else { - idempotencyKey = key - } - break - } - - case "finished": { - inProgress = false - break - } - - default: - idempotencyKey = await idempotencyKeyService.update( - idempotencyKey.idempotency_key, - { - recovery_point: "finished", - response_code: 500, - response_body: { message: "Unknown recovery point" }, - } - ) - break - } - } - - if (err) { - throw err - } - - res.status(idempotencyKey.response_code).json(idempotencyKey.response_body) + res.status(response_code).json(response_body) } diff --git a/packages/medusa/src/api/routes/store/carts/index.ts b/packages/medusa/src/api/routes/store/carts/index.ts index 536017b62c..f3d44c9f79 100644 --- a/packages/medusa/src/api/routes/store/carts/index.ts +++ b/packages/medusa/src/api/routes/store/carts/index.ts @@ -93,6 +93,12 @@ export default (app, container) => { middlewares.wrap(require("./add-shipping-method").default) ) + // Taxes + route.post( + "/:id/taxes", + middlewares.wrap(require("./calculate-taxes").default) + ) + return app } diff --git a/packages/medusa/src/api/routes/store/swaps/create-swap.ts b/packages/medusa/src/api/routes/store/swaps/create-swap.ts index e0701afd4e..856f3e0b27 100644 --- a/packages/medusa/src/api/routes/store/swaps/create-swap.ts +++ b/packages/medusa/src/api/routes/store/swaps/create-swap.ts @@ -128,7 +128,13 @@ export default async (req, res) => { .withTransaction(manager) .retrieve(swapDto.order_id, { select: ["refunded_total", "total"], - relations: ["items", "swaps", "swaps.additional_items"], + relations: [ + "items", + "items.tax_lines", + "swaps", + "swaps.additional_items", + "swaps.additional_items.tax_lines", + ], }) let returnShipping diff --git a/packages/medusa/src/helpers/test-request.js b/packages/medusa/src/helpers/test-request.js index 47d1930710..59c78154c2 100644 --- a/packages/medusa/src/helpers/test-request.js +++ b/packages/medusa/src/helpers/test-request.js @@ -8,6 +8,7 @@ import config from "../config" import apiLoader from "../loaders/api" import passportLoader from "../loaders/passport" import servicesLoader from "../loaders/services" +import strategiesLoader from "../loaders/strategies" const adminSessionOpts = { cookieName: "session", @@ -45,6 +46,7 @@ testApp.use((req, res, next) => { }) servicesLoader({ container }) +strategiesLoader({ container }) passportLoader({ app: testApp, container }) testApp.use((req, res, next) => { diff --git a/packages/medusa/src/index.js b/packages/medusa/src/index.js index 9d7205c29a..e3d92b9cda 100644 --- a/packages/medusa/src/index.js +++ b/packages/medusa/src/index.js @@ -1,55 +1,65 @@ // API payloads export * from "./api" +// Interfaces +export * from "./interfaces" + // Models -export { Address } from "./models/address" -export { Cart } from "./models/cart" -export { ClaimImage } from "./models/claim-image" -export { ClaimItem } from "./models/claim-item" -export { ClaimOrder } from "./models/claim-order" -export { ClaimTag } from "./models/claim-tag" -export { Country } from "./models/country" -export { Currency } from "./models/currency" -export { CustomShippingOption } from "./models/custom-shipping-option" -export { Customer } from "./models/customer" -export { CustomerGroup } from "./models/customer-group" -export { Discount } from "./models/discount" -export { DiscountRule } from "./models/discount-rule" -export { DraftOrder } from "./models/draft-order" -export { Fulfillment } from "./models/fulfillment" -export { FulfillmentItem } from "./models/fulfillment-item" -export { FulfillmentProvider } from "./models/fulfillment-provider" -export { GiftCard } from "./models/gift-card" -export { GiftCardTransaction } from "./models/gift-card-transaction" -export { IdempotencyKey } from "./models/idempotency-key" -export { Image } from "./models/image" -export { Invite } from "./models/invite" -export { LineItem } from "./models/line-item" -export { MoneyAmount } from "./models/money-amount" -export { Note } from "./models/note" -export { Notification } from "./models/notification" -export { Oauth } from "./models/oauth" -export { Order } from "./models/order" -export { Payment } from "./models/payment" -export { PaymentProvider } from "./models/payment-provider" -export { PaymentSession } from "./models/payment-session" -export { Product } from "./models/product" -export { ProductCollection } from "./models/product-collection" -export { ProductOption } from "./models/product-option" -export { ProductOptionValue } from "./models/product-option-value" -export { ProductTag } from "./models/product-tag" -export { ProductType } from "./models/product-type" -export { ProductVariant } from "./models/product-variant" -export { Refund } from "./models/refund" -export { Region } from "./models/region" -export { Return } from "./models/return" -export { ReturnItem } from "./models/return-item" -export { ReturnReason } from "./models/return-reason" -export { ShippingMethod } from "./models/shipping-method" -export { ShippingOption } from "./models/shipping-option" -export { ShippingOptionRequirement } from "./models/shipping-option-requirement" -export { ShippingProfile } from "./models/shipping-profile" -export { StagedJob } from "./models/staged-job" -export { Store } from "./models/store" -export { Swap } from "./models/swap" -export { User } from "./models/user" +export * from "./models/shipping-tax-rate" +export * from "./models/product-tax-rate" +export * from "./models/product-type-tax-rate" +export * from "./models/tax-rate" +export * from "./models/shipping-method-tax-line" +export * from "./models/line-item-tax-line" +export * from "./models/address" +export * from "./models/cart" +export * from "./models/claim-image" +export * from "./models/claim-item" +export * from "./models/claim-order" +export * from "./models/claim-tag" +export * from "./models/country" +export * from "./models/currency" +export * from "./models/custom-shipping-option" +export * from "./models/customer" +export * from "./models/customer-group" +export * from "./models/discount" +export * from "./models/discount-rule" +export * from "./models/draft-order" +export * from "./models/fulfillment" +export * from "./models/fulfillment-item" +export * from "./models/fulfillment-provider" +export * from "./models/gift-card" +export * from "./models/gift-card-transaction" +export * from "./models/idempotency-key" +export * from "./models/image" +export * from "./models/invite" +export * from "./models/line-item" +export * from "./models/money-amount" +export * from "./models/note" +export * from "./models/notification" +export * from "./models/oauth" +export * from "./models/order" +export * from "./models/payment" +export * from "./models/payment-provider" +export * from "./models/payment-session" +export * from "./models/product" +export * from "./models/product-collection" +export * from "./models/product-option" +export * from "./models/product-option-value" +export * from "./models/product-tag" +export * from "./models/product-type" +export * from "./models/product-variant" +export * from "./models/refund" +export * from "./models/region" +export * from "./models/return" +export * from "./models/return-item" +export * from "./models/return-reason" +export * from "./models/shipping-method" +export * from "./models/shipping-option" +export * from "./models/shipping-option-requirement" +export * from "./models/shipping-profile" +export * from "./models/staged-job" +export * from "./models/store" +export * from "./models/swap" +export * from "./models/user" +export * from "./models/tax-provider" diff --git a/packages/medusa/src/interfaces/cart-completion-strategy.ts b/packages/medusa/src/interfaces/cart-completion-strategy.ts new file mode 100644 index 0000000000..f819a79c6d --- /dev/null +++ b/packages/medusa/src/interfaces/cart-completion-strategy.ts @@ -0,0 +1,33 @@ +import { IdempotencyKey } from "../models/idempotency-key" +import { RequestContext } from "../types/request" + +export type CartCompletionResponse = { + /** The response code for the completion request */ + response_code: number + + /** The response body for the completion request */ + response_body: object +} + +export interface ICartCompletionStrategy { + /** + * Takes a cart id and completes the cart. This for example takes place when + * creating an order or confirming a swap. + * @param cartId - the id of the Cart to complete. + * @param idempotencyKey - the idempotency key for the request + * @param context - the request context for the completion request + * @return the response for the completion request + */ + complete( + cartId: string, + idempotencyKey: IdempotencyKey, + context: RequestContext + ): Promise +} + +export function isCartCompletionStrategy( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + object: any +): object is ICartCompletionStrategy { + return typeof object.complete === "function" +} diff --git a/packages/medusa/src/interfaces/index.ts b/packages/medusa/src/interfaces/index.ts new file mode 100644 index 0000000000..fd67023898 --- /dev/null +++ b/packages/medusa/src/interfaces/index.ts @@ -0,0 +1,3 @@ +export * from "./tax-calculation-strategy" +export * from "./cart-completion-strategy" +export * from "./tax-service" diff --git a/packages/medusa/src/interfaces/tax-calculation-strategy.ts b/packages/medusa/src/interfaces/tax-calculation-strategy.ts new file mode 100644 index 0000000000..3125a794a5 --- /dev/null +++ b/packages/medusa/src/interfaces/tax-calculation-strategy.ts @@ -0,0 +1,27 @@ +import { LineItem } from "../models/line-item" +import { TaxCalculationContext } from "./tax-service" +import { LineItemTaxLine } from "../models/line-item-tax-line" +import { ShippingMethodTaxLine } from "../models/shipping-method-tax-line" + +export interface ITaxCalculationStrategy { + /** + * Calculates the tax amount for a given set of line items under applicable + * tax conditions and calculation contexts. + * @param items - the line items to calculate the tax total for + * @param taxLines - the tax lines that applies to the calculation + * @param calculationContext - other details relevant for the calculation + * @return the tax total + */ + calculate( + items: LineItem[], + taxLines: (ShippingMethodTaxLine | LineItemTaxLine)[], + calculationContext: TaxCalculationContext + ): Promise +} + +export function isTaxCalculationStrategy( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + object: any +): object is ITaxCalculationStrategy { + return typeof object.calculate === "function" +} diff --git a/packages/medusa/src/interfaces/tax-service.ts b/packages/medusa/src/interfaces/tax-service.ts new file mode 100644 index 0000000000..92b3899a51 --- /dev/null +++ b/packages/medusa/src/interfaces/tax-service.ts @@ -0,0 +1,59 @@ +import { LineItem } from "../models/line-item" +import { Region } from "../models/region" +import { Address } from "../models/address" +import { ShippingMethod } from "../models/shipping-method" +import { Customer } from "../models/customer" +import { ProviderTaxLine, TaxServiceRate } from "../types/tax-service" +import { LineAllocationsMap } from "../types/totals" + +/** + * A shipping method and the tax rates that have been configured to apply to the + * shipping method. + */ +export type ShippingTaxCalculationLine = { + shipping_method: ShippingMethod + rates: TaxServiceRate[] +} + +/** + * A line item and the tax rates that have been configured to apply to the + * product contained in the line item. + */ +export type ItemTaxCalculationLine = { + item: LineItem + rates: TaxServiceRate[] +} + +/** + * Information relevant to a tax calculation, such as the shipping address where + * the items are going. + */ +export type TaxCalculationContext = { + shipping_address: Address | null + customer: Customer + region: Region + is_return: boolean + shipping_methods: ShippingMethod[] + allocation_map: LineAllocationsMap +} + +/** + * Interface to be implemented by tax provider plugins. The interface defines a + * single method `getTaxLines` that returns numerical rates to apply to line + * items and shipping methods. + */ +export interface ITaxService { + /** + * Retrieves the numerical tax lines for a calculation context. + * @param itemLines - the line item calculation lines + * @param itemLines - the shipping calculation lines + * @param context - other details relevant to the tax determination + * @return numerical tax rates that should apply to the provided calculation + * lines + */ + getTaxLines( + itemLines: ItemTaxCalculationLine[], + shippingLines: ShippingTaxCalculationLine[], + context: TaxCalculationContext + ): Promise +} diff --git a/packages/medusa/src/loaders/index.js b/packages/medusa/src/loaders/index.js index ea737820cc..beedad4134 100644 --- a/packages/medusa/src/loaders/index.js +++ b/packages/medusa/src/loaders/index.js @@ -16,9 +16,10 @@ import redisLoader from "./redis" import repositoriesLoader from "./repositories" import searchIndexLoader from "./search-index" import servicesLoader from "./services" +import strategiesLoader from "./strategies" import subscribersLoader from "./subscribers" -export default async ({ directory: rootDirectory, expressApp }) => { +export default async ({ directory: rootDirectory, expressApp, isTest }) => { const { configModule } = getConfigFile(rootDirectory, `medusa-config`) const container = createContainer() @@ -58,7 +59,7 @@ export default async ({ directory: rootDirectory, expressApp }) => { const modelsActivity = Logger.activity("Initializing models") track("MODELS_INIT_STARTED") - modelsLoader({ container, activityId: modelsActivity }) + modelsLoader({ container, activityId: modelsActivity, isTest }) const mAct = Logger.success(modelsActivity, "Models initialized") || {} track("MODELS_INIT_COMPLETED", { duration: mAct.duration }) @@ -74,7 +75,7 @@ export default async ({ directory: rootDirectory, expressApp }) => { const repoActivity = Logger.activity("Initializing repositories") track("REPOSITORIES_INIT_STARTED") - repositoriesLoader({ container, activityId: repoActivity }) || {} + repositoriesLoader({ container, activityId: repoActivity, isTest }) || {} const rAct = Logger.success(repoActivity, "Repositories initialized") || {} track("REPOSITORIES_INIT_COMPLETED", { duration: rAct.duration }) @@ -84,6 +85,7 @@ export default async ({ directory: rootDirectory, expressApp }) => { container, configModule, activityId: dbActivity, + isTest, }) const dbAct = Logger.success(dbActivity, "Database initialized") || {} track("DATABASE_INIT_COMPLETED", { duration: dbAct.duration }) @@ -92,12 +94,24 @@ export default async ({ directory: rootDirectory, expressApp }) => { manager: asValue(dbConnection.manager), }) + const stratActivity = Logger.activity("Initializing strategies") + track("STRATEGIES_INIT_STARTED") + strategiesLoader({ + container, + configModule, + activityId: stratActivity, + isTest, + }) + const stratAct = Logger.success(stratActivity, "Strategies initialized") || {} + track("STRATEGIES_INIT_COMPLETED", { duration: stratAct.duration }) + const servicesActivity = Logger.activity("Initializing services") track("SERVICES_INIT_STARTED") servicesLoader({ container, configModule, activityId: servicesActivity, + isTest, }) const servAct = Logger.success(servicesActivity, "Services initialized") || {} track("SERVICES_INIT_COMPLETED", { duration: servAct.duration }) diff --git a/packages/medusa/src/loaders/models.js b/packages/medusa/src/loaders/models.js index 14113fec16..a6628dccf7 100644 --- a/packages/medusa/src/loaders/models.js +++ b/packages/medusa/src/loaders/models.js @@ -9,13 +9,13 @@ import formatRegistrationName from "../utils/format-registration-name" * Registers all models in the model directory */ export default ({ container }, config = { register: true }) => { - let corePath = "../models/*.js" + const corePath = "../models/*.js" const coreFull = path.join(__dirname, corePath) const toReturn = [] const core = glob.sync(coreFull, { cwd: __dirname }) - core.forEach(fn => { + core.forEach((fn) => { const loaded = require(fn) Object.entries(loaded).map(([key, val]) => { diff --git a/packages/medusa/src/loaders/passport.js b/packages/medusa/src/loaders/passport.js index 26e4fdf3ee..09cac3521d 100644 --- a/packages/medusa/src/loaders/passport.js +++ b/packages/medusa/src/loaders/passport.js @@ -35,7 +35,7 @@ export default async ({ app, container }) => { passport.use( new JWTStrategy( { - jwtFromRequest: req => req.session.jwt, + jwtFromRequest: (req) => req.session.jwt, secretOrKey: config.jwtSecret, }, async (jwtPayload, done) => { diff --git a/packages/medusa/src/loaders/plugins.js b/packages/medusa/src/loaders/plugins.js index 1a1addae96..4638decbc8 100644 --- a/packages/medusa/src/loaders/plugins.js +++ b/packages/medusa/src/loaders/plugins.js @@ -1,7 +1,6 @@ import glob from "glob" import { EntitySchema } from "typeorm" import { - BaseModel, BaseService, PaymentService, FulfillmentService, @@ -17,6 +16,7 @@ import fs from "fs" import { asValue, asClass, asFunction, aliasTo } from "awilix" import { sync as existsSync } from "fs-exists-cached" +import { isTaxCalculationStrategy } from "../interfaces/tax-calculation-strategy" import formatRegistrationName from "../utils/format-registration-name" /** @@ -26,7 +26,7 @@ export default async ({ rootDirectory, container, app, activityId }) => { const resolved = getResolvedPlugins(rootDirectory) await Promise.all( - resolved.map(async pluginDetails => { + resolved.map(async (pluginDetails) => { registerRepositories(pluginDetails, container) await registerServices(pluginDetails, container) registerMedusaApi(pluginDetails, container) @@ -37,7 +37,7 @@ export default async ({ rootDirectory, container, app, activityId }) => { ) await Promise.all( - resolved.map(async pluginDetails => runLoaders(pluginDetails, container)) + resolved.map(async (pluginDetails) => runLoaders(pluginDetails, container)) ) } @@ -50,7 +50,7 @@ function getResolvedPlugins(rootDirectory) { const { plugins } = configModule - const resolved = plugins.map(plugin => { + const resolved = plugins.map((plugin) => { if (_.isString(plugin)) { return resolvePlugin(plugin) } @@ -75,7 +75,7 @@ function getResolvedPlugins(rootDirectory) { export async function registerPluginModels({ rootDirectory, container }) { const resolved = getResolvedPlugins(rootDirectory) await Promise.all( - resolved.map(async pluginDetails => { + resolved.map(async (pluginDetails) => { registerModels(pluginDetails, container) }) ) @@ -87,7 +87,7 @@ async function runLoaders(pluginDetails, container) { {} ) await Promise.all( - loaderFiles.map(async loader => { + loaderFiles.map(async (loader) => { try { const module = require(loader).default if (typeof module === "function") { @@ -104,6 +104,34 @@ async function runLoaders(pluginDetails, container) { function registerMedusaApi(pluginDetails, container) { registerMedusaMiddleware(pluginDetails, container) + registerStrategies(pluginDetails, container) +} + +function registerStrategies(pluginDetails, container) { + let module + try { + const path = `${pluginDetails.resolve}/strategies/tax-calculation` + if (existsSync(path)) { + module = require(path).default + } else { + return + } + } catch (err) { + return + } + + if (isTaxCalculationStrategy(module.prototype)) { + container.register({ + taxCalculationStrategy: asFunction( + (cradle) => new module(cradle, pluginDetails.options) + ).singleton(), + }) + } else { + const logger = container.resolve("logger") + logger.warn( + `${pluginDetails.resolve}/strategies/tax-calculation did not export a class that implements ITaxCalculationStrategy. Your Medusa server will still work, but if you have written custom tax calculation logic it will not be used. Make sure to implement the ITaxCalculationStrategy interface.` + ) + } } function registerMedusaMiddleware(pluginDetails, container) { @@ -140,7 +168,7 @@ function registerCoreRouters(pluginDetails, container) { const adminFiles = glob.sync(`${resolve}/api/admin/[!__]*.js`, {}) const storeFiles = glob.sync(`${resolve}/api/store/[!__]*.js`, {}) - adminFiles.forEach(fn => { + adminFiles.forEach((fn) => { const descriptor = fn.split(".")[0] const splat = descriptor.split("/") const path = `${splat[splat.length - 2]}/${splat[splat.length - 1]}` @@ -148,7 +176,7 @@ function registerCoreRouters(pluginDetails, container) { middlewareService.addRouter(path, loaded()) }) - storeFiles.forEach(fn => { + storeFiles.forEach((fn) => { const descriptor = fn.split(".")[0] const splat = descriptor.split("/") const path = `${splat[splat.length - 2]}/${splat[splat.length - 1]}` @@ -204,7 +232,7 @@ function registerApi( async function registerServices(pluginDetails, container) { const files = glob.sync(`${pluginDetails.resolve}/services/[!__]*`, {}) await Promise.all( - files.map(async fn => { + files.map(async (fn) => { const loaded = require(fn).default const name = formatRegistrationName(fn) @@ -219,14 +247,14 @@ async function registerServices(pluginDetails, container) { // Register our payment providers to paymentProviders container.registerAdd( "paymentProviders", - asFunction(cradle => new loaded(cradle, pluginDetails.options)) + asFunction((cradle) => new loaded(cradle, pluginDetails.options)) ) // Add the service directly to the container in order to make simple // resolution if we already know which payment provider we need to use container.register({ [name]: asFunction( - cradle => new loaded(cradle, pluginDetails.options) + (cradle) => new loaded(cradle, pluginDetails.options) ), [`pp_${loaded.identifier}`]: aliasTo(name), }) @@ -239,35 +267,35 @@ async function registerServices(pluginDetails, container) { const name = appDetails.application_name container.register({ [`${name}Oauth`]: asFunction( - cradle => new loaded(cradle, pluginDetails.options) + (cradle) => new loaded(cradle, pluginDetails.options) ), }) } else if (loaded.prototype instanceof FulfillmentService) { // Register our payment providers to paymentProviders container.registerAdd( "fulfillmentProviders", - asFunction(cradle => new loaded(cradle, pluginDetails.options)) + asFunction((cradle) => new loaded(cradle, pluginDetails.options)) ) // Add the service directly to the container in order to make simple // resolution if we already know which fulfillment provider we need to use container.register({ [name]: asFunction( - cradle => new loaded(cradle, pluginDetails.options) + (cradle) => new loaded(cradle, pluginDetails.options) ).singleton(), [`fp_${loaded.identifier}`]: aliasTo(name), }) } else if (loaded.prototype instanceof NotificationService) { container.registerAdd( "notificationProviders", - asFunction(cradle => new loaded(cradle, pluginDetails.options)) + asFunction((cradle) => new loaded(cradle, pluginDetails.options)) ) // Add the service directly to the container in order to make simple // resolution if we already know which notification provider we need to use container.register({ [name]: asFunction( - cradle => new loaded(cradle, pluginDetails.options) + (cradle) => new loaded(cradle, pluginDetails.options) ).singleton(), [`noti_${loaded.identifier}`]: aliasTo(name), }) @@ -276,7 +304,7 @@ async function registerServices(pluginDetails, container) { // resolution if we already know which file storage provider we need to use container.register({ [name]: asFunction( - cradle => new loaded(cradle, pluginDetails.options) + (cradle) => new loaded(cradle, pluginDetails.options) ), [`fileService`]: aliasTo(name), }) @@ -285,14 +313,14 @@ async function registerServices(pluginDetails, container) { // resolution if we already know which search provider we need to use container.register({ [name]: asFunction( - cradle => new loaded(cradle, pluginDetails.options) + (cradle) => new loaded(cradle, pluginDetails.options) ), [`searchService`]: aliasTo(name), }) } else { container.register({ [name]: asFunction( - cradle => new loaded(cradle, pluginDetails.options) + (cradle) => new loaded(cradle, pluginDetails.options) ), }) } @@ -311,13 +339,13 @@ async function registerServices(pluginDetails, container) { */ function registerSubscribers(pluginDetails, container) { const files = glob.sync(`${pluginDetails.resolve}/subscribers/*.js`, {}) - files.forEach(fn => { + files.forEach((fn) => { const loaded = require(fn).default const name = formatRegistrationName(fn) container.build( asFunction( - cradle => new loaded(cradle, pluginDetails.options) + (cradle) => new loaded(cradle, pluginDetails.options) ).singleton() ) }) @@ -334,7 +362,7 @@ function registerSubscribers(pluginDetails, container) { */ function registerRepositories(pluginDetails, container) { const files = glob.sync(`${pluginDetails.resolve}/repositories/*.js`, {}) - files.forEach(fn => { + files.forEach((fn) => { const loaded = require(fn) Object.entries(loaded).map(([key, val]) => { @@ -361,7 +389,7 @@ function registerRepositories(pluginDetails, container) { */ function registerModels(pluginDetails, container) { const files = glob.sync(`${pluginDetails.resolve}/models/*.js`, {}) - files.forEach(fn => { + files.forEach((fn) => { const loaded = require(fn) Object.entries(loaded).map(([key, val]) => { diff --git a/packages/medusa/src/loaders/services.js b/packages/medusa/src/loaders/services.js index 6a203779ea..170ca8f5db 100644 --- a/packages/medusa/src/loaders/services.js +++ b/packages/medusa/src/loaders/services.js @@ -7,20 +7,21 @@ import formatRegistrationName from "../utils/format-registration-name" /** * Registers all services in the services directory */ -export default ({ container, configModule }) => { - const isTest = process.env.NODE_ENV === "test" +export default ({ container, configModule, isTest }) => { + const useMock = + typeof isTest !== "undefined" ? isTest : process.env.NODE_ENV === "test" - const corePath = isTest ? "../services/__mocks__/*.js" : "../services/*.js" + const corePath = useMock ? "../services/__mocks__/*.js" : "../services/*.js" const coreFull = path.join(__dirname, corePath) const core = glob.sync(coreFull, { cwd: __dirname }) - core.forEach(fn => { + core.forEach((fn) => { const loaded = require(fn).default if (loaded) { const name = formatRegistrationName(fn) container.register({ [name]: asFunction( - cradle => new loaded(cradle, configModule), + (cradle) => new loaded(cradle, configModule) ).singleton(), }) } diff --git a/packages/medusa/src/loaders/strategies.ts b/packages/medusa/src/loaders/strategies.ts new file mode 100644 index 0000000000..be97e95c1c --- /dev/null +++ b/packages/medusa/src/loaders/strategies.ts @@ -0,0 +1,37 @@ +import glob from "glob" +import path from "path" +import { AwilixContainer, asFunction } from "awilix" + +import formatRegistrationName from "../utils/format-registration-name" + +type LoaderOptions = { + container: AwilixContainer + configModule: object + isTest: boolean +} + +/** + * Registers all strategies in the strategies directory + * @returns void + */ +export default ({ container, configModule, isTest }: LoaderOptions): void => { + const useMock = + typeof isTest !== "undefined" ? isTest : process.env.NODE_ENV === "test" + + const corePath = useMock + ? "../strategies/__mocks__/*.js" + : "../strategies/*.js" + const coreFull = path.join(__dirname, corePath) + + const core = glob.sync(coreFull, { cwd: __dirname }) + core.forEach((fn) => { + // eslint-disable-next-line @typescript-eslint/no-var-requires + const loaded = require(fn).default + const name = formatRegistrationName(fn) + container.register({ + [name]: asFunction( + (cradle) => new loaded(cradle, configModule) + ).singleton(), + }) + }) +} diff --git a/packages/medusa/src/migrations/1641636508055-new_tax_system.ts b/packages/medusa/src/migrations/1641636508055-new_tax_system.ts new file mode 100644 index 0000000000..202240a195 --- /dev/null +++ b/packages/medusa/src/migrations/1641636508055-new_tax_system.ts @@ -0,0 +1,178 @@ +import { MigrationInterface, QueryRunner } from "typeorm" + +export class newTaxSystem1641636508055 implements MigrationInterface { + name = "newTaxSystem1641636508055" + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "tax_rate" ("id" character varying NOT NULL, "rate" real, "code" character varying, "name" character varying NOT NULL, "region_id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "metadata" jsonb, CONSTRAINT "PK_23b71b53f650c0b39e99ccef4fd" PRIMARY KEY ("id"))` + ) + await queryRunner.query( + `CREATE TABLE "tax_provider" ("id" character varying NOT NULL, "is_installed" boolean NOT NULL DEFAULT true, CONSTRAINT "PK_b198bf82ba6a317c11763d99b99" PRIMARY KEY ("id"))` + ) + await queryRunner.query( + `CREATE TABLE "line_item_tax_line" ("id" character varying NOT NULL, "rate" real NOT NULL, "name" character varying NOT NULL, "code" character varying, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "metadata" jsonb, "item_id" character varying NOT NULL, CONSTRAINT "PK_4a0f4322fcd5ce4af85727f89a8" PRIMARY KEY ("id"))` + ) + await queryRunner.query( + `CREATE INDEX "IDX_5077fa54b0d037e984385dfe8a" ON "line_item_tax_line" ("item_id") ` + ) + await queryRunner.query( + `CREATE TABLE "shipping_method_tax_line" ("id" character varying NOT NULL, "rate" real NOT NULL, "name" character varying NOT NULL, "code" character varying, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "metadata" jsonb, "shipping_method_id" character varying NOT NULL, CONSTRAINT "PK_54c94f5908aacbd51cf0a73edb1" PRIMARY KEY ("id"))` + ) + await queryRunner.query( + `CREATE INDEX "IDX_926ca9f29014af8091722dede0" ON "shipping_method_tax_line" ("shipping_method_id") ` + ) + await queryRunner.query( + `CREATE TABLE "product_tax_rate" ("product_id" character varying NOT NULL, "rate_id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "metadata" jsonb, CONSTRAINT "PK_326257ce468df46cd5c8c5922e9" PRIMARY KEY ("product_id", "rate_id"))` + ) + await queryRunner.query( + `CREATE TABLE "product_type_tax_rate" ("product_type_id" character varying NOT NULL, "rate_id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "metadata" jsonb, CONSTRAINT "PK_ddc9242de1d99bc7674969289f0" PRIMARY KEY ("product_type_id", "rate_id"))` + ) + await queryRunner.query( + `CREATE TABLE "shipping_tax_rate" ("shipping_option_id" character varying NOT NULL, "rate_id" character varying NOT NULL, "created_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "updated_at" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), "metadata" jsonb, CONSTRAINT "PK_bcd93b14d7e2695365d383f5eae" PRIMARY KEY ("shipping_option_id", "rate_id"))` + ) + await queryRunner.query( + `ALTER TABLE "region" ADD "gift_cards_taxable" boolean NOT NULL DEFAULT true` + ) + await queryRunner.query( + `ALTER TABLE "region" ADD "automatic_taxes" boolean NOT NULL DEFAULT true` + ) + await queryRunner.query( + `ALTER TABLE "region" ADD "tax_provider_id" character varying` + ) + await queryRunner.query( + `ALTER TABLE "line_item" ADD "is_return" boolean NOT NULL DEFAULT false` + ) + await queryRunner.query( + `UPDATE "line_item" SET "is_return" = true WHERE "id" IN (SELECT "id" from "line_item" WHERE "metadata"->>'is_return_line' = 'true')` + ) + await queryRunner.query( + `ALTER TABLE "order" ALTER COLUMN "tax_rate" DROP NOT NULL` + ) + await queryRunner.query( + `CREATE INDEX "IDX_2484cf14c437a04586b07e7ddd" ON "product_tax_rate" ("rate_id") ` + ) + await queryRunner.query( + `CREATE INDEX "IDX_1d04aebeabb6a89f87e536a124" ON "product_tax_rate" ("product_id") ` + ) + await queryRunner.query( + `CREATE INDEX "IDX_ece65a774192b34253abc4cd67" ON "product_type_tax_rate" ("rate_id") ` + ) + await queryRunner.query( + `CREATE INDEX "IDX_25a3138bb236f63d9bb6c8ff11" ON "product_type_tax_rate" ("product_type_id") ` + ) + await queryRunner.query( + `CREATE INDEX "IDX_346e0016cf045b998074774764" ON "shipping_tax_rate" ("rate_id") ` + ) + await queryRunner.query( + `CREATE INDEX "IDX_f672727ab020df6c50fb64c1a7" ON "shipping_tax_rate" ("shipping_option_id") ` + ) + await queryRunner.query( + `ALTER TABLE "tax_rate" ADD CONSTRAINT "FK_b95a1e03b051993d208366cb960" FOREIGN KEY ("region_id") REFERENCES "region"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "region" ADD CONSTRAINT "FK_91f88052197680f9790272aaf5b" FOREIGN KEY ("tax_provider_id") REFERENCES "tax_provider"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "line_item_tax_line" ADD CONSTRAINT "FK_5077fa54b0d037e984385dfe8ad" FOREIGN KEY ("item_id") REFERENCES "line_item"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "shipping_method_tax_line" ADD CONSTRAINT "FK_926ca9f29014af8091722dede08" FOREIGN KEY ("shipping_method_id") REFERENCES "shipping_method"("id") ON DELETE NO ACTION ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "product_tax_rate" ADD CONSTRAINT "FK_1d04aebeabb6a89f87e536a124d" FOREIGN KEY ("product_id") REFERENCES "product"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "product_tax_rate" ADD CONSTRAINT "FK_2484cf14c437a04586b07e7dddb" FOREIGN KEY ("rate_id") REFERENCES "tax_rate"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "product_type_tax_rate" ADD CONSTRAINT "FK_25a3138bb236f63d9bb6c8ff111" FOREIGN KEY ("product_type_id") REFERENCES "product_type"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "product_type_tax_rate" ADD CONSTRAINT "FK_ece65a774192b34253abc4cd672" FOREIGN KEY ("rate_id") REFERENCES "tax_rate"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "shipping_tax_rate" ADD CONSTRAINT "FK_f672727ab020df6c50fb64c1a70" FOREIGN KEY ("shipping_option_id") REFERENCES "shipping_option"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) + await queryRunner.query( + `ALTER TABLE "shipping_tax_rate" ADD CONSTRAINT "FK_346e0016cf045b9980747747645" FOREIGN KEY ("rate_id") REFERENCES "tax_rate"("id") ON DELETE CASCADE ON UPDATE NO ACTION` + ) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "shipping_tax_rate" DROP CONSTRAINT "FK_346e0016cf045b9980747747645"` + ) + await queryRunner.query( + `ALTER TABLE "shipping_tax_rate" DROP CONSTRAINT "FK_f672727ab020df6c50fb64c1a70"` + ) + await queryRunner.query( + `ALTER TABLE "product_type_tax_rate" DROP CONSTRAINT "FK_ece65a774192b34253abc4cd672"` + ) + await queryRunner.query( + `ALTER TABLE "product_type_tax_rate" DROP CONSTRAINT "FK_25a3138bb236f63d9bb6c8ff111"` + ) + await queryRunner.query( + `ALTER TABLE "product_tax_rate" DROP CONSTRAINT "FK_2484cf14c437a04586b07e7dddb"` + ) + await queryRunner.query( + `ALTER TABLE "product_tax_rate" DROP CONSTRAINT "FK_1d04aebeabb6a89f87e536a124d"` + ) + await queryRunner.query( + `ALTER TABLE "shipping_method_tax_line" DROP CONSTRAINT "FK_926ca9f29014af8091722dede08"` + ) + await queryRunner.query( + `ALTER TABLE "line_item_tax_line" DROP CONSTRAINT "FK_5077fa54b0d037e984385dfe8ad"` + ) + await queryRunner.query( + `ALTER TABLE "region" DROP CONSTRAINT "FK_91f88052197680f9790272aaf5b"` + ) + await queryRunner.query( + `ALTER TABLE "tax_rate" DROP CONSTRAINT "FK_b95a1e03b051993d208366cb960"` + ) + await queryRunner.query( + `DROP INDEX "public"."IDX_f672727ab020df6c50fb64c1a7"` + ) + await queryRunner.query( + `DROP INDEX "public"."IDX_346e0016cf045b998074774764"` + ) + await queryRunner.query( + `DROP INDEX "public"."IDX_25a3138bb236f63d9bb6c8ff11"` + ) + await queryRunner.query( + `DROP INDEX "public"."IDX_ece65a774192b34253abc4cd67"` + ) + await queryRunner.query( + `DROP INDEX "public"."IDX_1d04aebeabb6a89f87e536a124"` + ) + await queryRunner.query( + `DROP INDEX "public"."IDX_2484cf14c437a04586b07e7ddd"` + ) + await queryRunner.query( + `ALTER TABLE "order" ALTER COLUMN "tax_rate" SET NOT NULL` + ) + await queryRunner.query(`ALTER TABLE "line_item" DROP COLUMN "is_return"`) + await queryRunner.query( + `ALTER TABLE "region" DROP COLUMN "tax_provider_id"` + ) + await queryRunner.query( + `ALTER TABLE "region" DROP COLUMN "automatic_taxes"` + ) + await queryRunner.query( + `ALTER TABLE "region" DROP COLUMN "gift_cards_taxable"` + ) + await queryRunner.query(`DROP TABLE "shipping_tax_rate"`) + await queryRunner.query(`DROP TABLE "product_type_tax_rate"`) + await queryRunner.query(`DROP TABLE "product_tax_rate"`) + await queryRunner.query( + `DROP INDEX "public"."IDX_926ca9f29014af8091722dede0"` + ) + await queryRunner.query(`DROP TABLE "shipping_method_tax_line"`) + await queryRunner.query( + `DROP INDEX "public"."IDX_5077fa54b0d037e984385dfe8a"` + ) + await queryRunner.query(`DROP TABLE "line_item_tax_line"`) + await queryRunner.query(`DROP TABLE "tax_provider"`) + await queryRunner.query(`DROP TABLE "tax_rate"`) + } +} diff --git a/packages/medusa/src/models/cart.ts b/packages/medusa/src/models/cart.ts index e72b0730dd..496e86b697 100644 --- a/packages/medusa/src/models/cart.ts +++ b/packages/medusa/src/models/cart.ts @@ -124,6 +124,8 @@ export class Cart { @PrimaryColumn() id: string + readonly object = "cart" + @Column({ nullable: true }) email: string @@ -245,7 +247,7 @@ export class Cart { shipping_total?: number discount_total?: number - tax_total?: number + tax_total?: number | null refunded_total?: number total?: number subtotal?: number diff --git a/packages/medusa/src/models/line-item-tax-line.ts b/packages/medusa/src/models/line-item-tax-line.ts new file mode 100644 index 0000000000..f65facec59 --- /dev/null +++ b/packages/medusa/src/models/line-item-tax-line.ts @@ -0,0 +1,30 @@ +import { + Entity, + BeforeInsert, + Index, + Column, + ManyToOne, + JoinColumn, +} from "typeorm" +import { ulid } from "ulid" + +import { TaxLine } from "./tax-line" +import { LineItem } from "./line-item" + +@Entity() +export class LineItemTaxLine extends TaxLine { + @Index() + @Column() + item_id: string + + @ManyToOne(() => LineItem, (li) => li.tax_lines) + @JoinColumn({ name: "item_id" }) + item: LineItem + + @BeforeInsert() + private beforeInsert() { + if (this.id) return + const id = ulid() + this.id = `litl_${id}` + } +} diff --git a/packages/medusa/src/models/line-item.ts b/packages/medusa/src/models/line-item.ts index 0a3bff8639..d722fe4a70 100644 --- a/packages/medusa/src/models/line-item.ts +++ b/packages/medusa/src/models/line-item.ts @@ -1,5 +1,6 @@ import { Entity, + OneToMany, BeforeInsert, CreateDateColumn, UpdateDateColumn, @@ -13,6 +14,7 @@ import { import { ulid } from "ulid" import { resolveDbType, DbAwareColumn } from "../utils/db-aware-column" +import { LineItemTaxLine } from "./line-item-tax-line" import { Swap } from "./swap" import { Cart } from "./cart" import { Order } from "./order" @@ -32,10 +34,7 @@ export class LineItem { @Column({ nullable: true }) cart_id: string - @ManyToOne( - () => Cart, - cart => cart.items - ) + @ManyToOne(() => Cart, (cart) => cart.items) @JoinColumn({ name: "cart_id" }) cart: Cart @@ -43,10 +42,7 @@ export class LineItem { @Column({ nullable: true }) order_id: string - @ManyToOne( - () => Order, - order => order.items - ) + @ManyToOne(() => Order, (order) => order.items) @JoinColumn({ name: "order_id" }) order: Order @@ -54,10 +50,7 @@ export class LineItem { @Column({ nullable: true }) swap_id: string - @ManyToOne( - () => Swap, - swap => swap.additional_items - ) + @ManyToOne(() => Swap, (swap) => swap.additional_items) @JoinColumn({ name: "swap_id" }) swap: Swap @@ -65,13 +58,13 @@ export class LineItem { @Column({ nullable: true }) claim_order_id: string - @ManyToOne( - () => ClaimOrder, - co => co.additional_items - ) + @ManyToOne(() => ClaimOrder, (co) => co.additional_items) @JoinColumn({ name: "claim_order_id" }) claim_order: ClaimOrder + @OneToMany(() => LineItemTaxLine, (tl) => tl.item, { cascade: ["insert"] }) + tax_lines: LineItemTaxLine[] + @Column() title: string @@ -81,6 +74,9 @@ export class LineItem { @Column({ nullable: true }) thumbnail: string + @Column({ default: false }) + is_return: boolean + @Column({ default: false }) is_giftcard: boolean diff --git a/packages/medusa/src/models/order.ts b/packages/medusa/src/models/order.ts index a64de6707a..0f3e02f604 100644 --- a/packages/medusa/src/models/order.ts +++ b/packages/medusa/src/models/order.ts @@ -74,6 +74,8 @@ export class Order { @PrimaryColumn() id: string + readonly object = "order" + @DbAwareColumn({ type: "enum", enum: OrderStatus, default: "pending" }) status: OrderStatus @@ -142,8 +144,8 @@ export class Order { @JoinColumn({ name: "currency_code", referencedColumnName: "code" }) currency: Currency - @Column({ type: "real" }) - tax_rate: number + @Column({ type: "real", nullable: true }) + tax_rate: number | null @ManyToMany(() => Discount, { cascade: ["insert"] }) @JoinTable({ @@ -173,57 +175,29 @@ export class Order { }) gift_cards: GiftCard[] - @OneToMany( - () => ShippingMethod, - (method) => method.order, - { - cascade: ["insert"], - } - ) + @OneToMany(() => ShippingMethod, (method) => method.order, { + cascade: ["insert"], + }) shipping_methods: ShippingMethod[] - @OneToMany( - () => Payment, - (payment) => payment.order, - { cascade: ["insert"] } - ) + @OneToMany(() => Payment, (payment) => payment.order, { cascade: ["insert"] }) payments: Payment[] - @OneToMany( - () => Fulfillment, - (fulfillment) => fulfillment.order, - { - cascade: ["insert"], - } - ) + @OneToMany(() => Fulfillment, (fulfillment) => fulfillment.order, { + cascade: ["insert"], + }) fulfillments: Fulfillment[] - @OneToMany( - () => Return, - (ret) => ret.order, - { cascade: ["insert"] } - ) + @OneToMany(() => Return, (ret) => ret.order, { cascade: ["insert"] }) returns: Return[] - @OneToMany( - () => ClaimOrder, - (co) => co.order, - { cascade: ["insert"] } - ) + @OneToMany(() => ClaimOrder, (co) => co.order, { cascade: ["insert"] }) claims: ClaimOrder[] - @OneToMany( - () => Refund, - (ref) => ref.order, - { cascade: ["insert"] } - ) + @OneToMany(() => Refund, (ref) => ref.order, { cascade: ["insert"] }) refunds: Refund[] - @OneToMany( - () => Swap, - (swap) => swap.order, - { cascade: ["insert"] } - ) + @OneToMany(() => Swap, (swap) => swap.order, { cascade: ["insert"] }) swaps: Swap[] @Column({ nullable: true }) @@ -233,19 +207,12 @@ export class Order { @JoinColumn({ name: "draft_order_id" }) draft_order: DraftOrder - @OneToMany( - () => LineItem, - (lineItem) => lineItem.order, - { - cascade: ["insert"], - } - ) + @OneToMany(() => LineItem, (lineItem) => lineItem.order, { + cascade: ["insert"], + }) items: LineItem[] - @OneToMany( - () => GiftCardTransaction, - (gc) => gc.order - ) + @OneToMany(() => GiftCardTransaction, (gc) => gc.order) gift_card_transactions: GiftCardTransaction[] @Column({ nullable: true, type: resolveDbType("timestamptz") }) diff --git a/packages/medusa/src/models/product-tax-rate.ts b/packages/medusa/src/models/product-tax-rate.ts new file mode 100644 index 0000000000..8b3f036ceb --- /dev/null +++ b/packages/medusa/src/models/product-tax-rate.ts @@ -0,0 +1,69 @@ +import { + Entity, + DeleteDateColumn, + CreateDateColumn, + UpdateDateColumn, + ManyToOne, + JoinColumn, + PrimaryColumn, +} from "typeorm" +import { resolveDbType, DbAwareColumn } from "../utils/db-aware-column" + +import { Product } from "./product" +import { TaxRate } from "./tax-rate" + +@Entity() +export class ProductTaxRate { + @PrimaryColumn() + product_id: string + + @PrimaryColumn() + rate_id: string + + @ManyToOne(() => Product, { onDelete: "CASCADE" }) + @JoinColumn({ name: "product_id" }) + product?: Product + + // Note the onDelete config here + @ManyToOne(() => TaxRate, { onDelete: "CASCADE" }) + @JoinColumn({ name: "rate_id" }) + tax_rate?: TaxRate + + @CreateDateColumn({ type: resolveDbType("timestamptz") }) + created_at: Date + + @UpdateDateColumn({ type: resolveDbType("timestamptz") }) + updated_at: Date + + @DbAwareColumn({ type: "jsonb", nullable: true }) + metadata: any +} + +/** + * @schema product_tax_rate + * title: "Product Tax Rate" + * description: "Associates a tax rate with a product to indicate that the product is taxed in a certain way" + * x-resourceId: product_tax_rate + * properties: + * product_id: + * description: "The id of the Product" + * type: string + * rate_id: + * description: "The id of the Tax Rate" + * type: string + * created_at: + * description: "The date with timezone at which the resource was created." + * type: string + * format: date-time + * updated_at: + * description: "The date with timezone at which the resource was last updated." + * type: string + * format: date-time + * deleted_at: + * description: "The date with timezone at which the resource was deleted." + * type: string + * format: date-time + * metadata: + * description: "An optional key-value map with additional information." + * type: object + */ diff --git a/packages/medusa/src/models/product-type-tax-rate.ts b/packages/medusa/src/models/product-type-tax-rate.ts new file mode 100644 index 0000000000..6df9112d5e --- /dev/null +++ b/packages/medusa/src/models/product-type-tax-rate.ts @@ -0,0 +1,68 @@ +import { + Entity, + DeleteDateColumn, + CreateDateColumn, + UpdateDateColumn, + ManyToOne, + JoinColumn, + PrimaryColumn, +} from "typeorm" +import { resolveDbType, DbAwareColumn } from "../utils/db-aware-column" + +import { ProductType } from "./product-type" +import { TaxRate } from "./tax-rate" + +@Entity() +export class ProductTypeTaxRate { + @PrimaryColumn() + product_type_id: string + + @PrimaryColumn() + rate_id: string + + @ManyToOne(() => ProductType, { onDelete: "CASCADE" }) + @JoinColumn({ name: "product_type_id" }) + product_type?: ProductType + + @ManyToOne(() => TaxRate, { onDelete: "CASCADE" }) + @JoinColumn({ name: "rate_id" }) + tax_rate?: TaxRate + + @CreateDateColumn({ type: resolveDbType("timestamptz") }) + created_at: Date + + @UpdateDateColumn({ type: resolveDbType("timestamptz") }) + updated_at: Date + + @DbAwareColumn({ type: "jsonb", nullable: true }) + metadata: any +} + +/** + * @schema product_type_tax_rate + * title: "Product Type Tax Rate" + * description: "Associates a tax rate with a product type to indicate that the product type is taxed in a certain way" + * x-resourceId: product_type_tax_rate + * properties: + * product_type_id: + * description: "The id of the Product type" + * type: string + * rate_id: + * description: "The id of the Tax Rate" + * type: string + * created_at: + * description: "The date with timezone at which the resource was created." + * type: string + * format: date-time + * updated_at: + * description: "The date with timezone at which the resource was last updated." + * type: string + * format: date-time + * deleted_at: + * description: "The date with timezone at which the resource was deleted." + * type: string + * format: date-time + * metadata: + * description: "An optional key-value map with additional information." + * type: object + */ diff --git a/packages/medusa/src/models/region.ts b/packages/medusa/src/models/region.ts index d54df230b6..dc3d7f1308 100644 --- a/packages/medusa/src/models/region.ts +++ b/packages/medusa/src/models/region.ts @@ -16,9 +16,11 @@ import { ulid } from "ulid" import { resolveDbType, DbAwareColumn } from "../utils/db-aware-column" import { Currency } from "./currency" +import { TaxRate } from "./tax-rate" import { Country } from "./country" import { PaymentProvider } from "./payment-provider" import { FulfillmentProvider } from "./fulfillment-provider" +import { TaxProvider } from "./tax-provider" @Entity() export class Region { @@ -38,16 +40,32 @@ export class Region { @Column({ type: "real" }) tax_rate: number + @OneToMany(() => TaxRate, (tr) => tr.region) + tax_rates: TaxRate[] | null + @Column({ nullable: true }) tax_code: string - @OneToMany( - () => Country, - c => c.region - ) + @Column({ default: true }) + gift_cards_taxable: boolean + + @Column({ default: true }) + automatic_taxes: boolean + + @OneToMany(() => Country, (c) => c.region) countries: Country[] - @ManyToMany(() => PaymentProvider, { eager: true, cascade: ['insert', 'update'] }) + @Column({ type: "text", nullable: true }) + tax_provider_id: string | null + + @ManyToOne(() => TaxProvider) + @JoinColumn({ name: "tax_provider_id" }) + tax_provider: TaxProvider + + @ManyToMany(() => PaymentProvider, { + eager: true, + cascade: ["insert", "update"], + }) @JoinTable({ name: "region_payment_providers", joinColumn: { @@ -61,7 +79,10 @@ export class Region { }) payment_providers: PaymentProvider[] - @ManyToMany(() => FulfillmentProvider, { eager: true, cascade: ['insert', 'update'] }) + @ManyToMany(() => FulfillmentProvider, { + eager: true, + cascade: ["insert", "update"], + }) @JoinTable({ name: "region_fulfillment_providers", joinColumn: { diff --git a/packages/medusa/src/models/shipping-method-tax-line.ts b/packages/medusa/src/models/shipping-method-tax-line.ts new file mode 100644 index 0000000000..606f4b427c --- /dev/null +++ b/packages/medusa/src/models/shipping-method-tax-line.ts @@ -0,0 +1,30 @@ +import { + Entity, + BeforeInsert, + Index, + Column, + ManyToOne, + JoinColumn, +} from "typeorm" +import { ulid } from "ulid" + +import { TaxLine } from "./tax-line" +import { ShippingMethod } from "./shipping-method" + +@Entity() +export class ShippingMethodTaxLine extends TaxLine { + @Index() + @Column() + shipping_method_id: string + + @ManyToOne(() => ShippingMethod, (sm) => sm.tax_lines) + @JoinColumn({ name: "shipping_method_id" }) + shipping_method: ShippingMethod + + @BeforeInsert() + private beforeInsert() { + if (this.id) return + const id = ulid() + this.id = `smtl_${id}` + } +} diff --git a/packages/medusa/src/models/shipping-method.ts b/packages/medusa/src/models/shipping-method.ts index 4f63ae8304..210b18ec82 100644 --- a/packages/medusa/src/models/shipping-method.ts +++ b/packages/medusa/src/models/shipping-method.ts @@ -6,6 +6,7 @@ import { PrimaryColumn, ManyToOne, OneToOne, + OneToMany, JoinColumn, Index, } from "typeorm" @@ -18,6 +19,7 @@ import { Cart } from "./cart" import { Swap } from "./swap" import { Return } from "./return" import { ShippingOption } from "./shipping-option" +import { ShippingMethodTaxLine } from "./shipping-method-tax-line" @Check( `"claim_order_id" IS NOT NULL OR "order_id" IS NOT NULL OR "cart_id" IS NOT NULL OR "swap_id" IS NOT NULL OR "return_id" IS NOT NULL` @@ -68,10 +70,7 @@ export class ShippingMethod { @Column({ nullable: true }) return_id: string - @OneToOne( - () => Return, - ret => ret.shipping_method - ) + @OneToOne(() => Return, (ret) => ret.shipping_method) @JoinColumn({ name: "return_id" }) return_order: Return @@ -79,6 +78,11 @@ export class ShippingMethod { @JoinColumn({ name: "shipping_option_id" }) shipping_option: ShippingOption + @OneToMany(() => ShippingMethodTaxLine, (tl) => tl.shipping_method, { + cascade: ["insert"], + }) + tax_lines: ShippingMethodTaxLine[] + @Column({ type: "int" }) price: number diff --git a/packages/medusa/src/models/shipping-tax-rate.ts b/packages/medusa/src/models/shipping-tax-rate.ts new file mode 100644 index 0000000000..15ac9246bd --- /dev/null +++ b/packages/medusa/src/models/shipping-tax-rate.ts @@ -0,0 +1,68 @@ +import { + Entity, + DeleteDateColumn, + CreateDateColumn, + UpdateDateColumn, + ManyToOne, + JoinColumn, + PrimaryColumn, +} from "typeorm" +import { resolveDbType, DbAwareColumn } from "../utils/db-aware-column" + +import { ShippingOption } from "./shipping-option" +import { TaxRate } from "./tax-rate" + +@Entity() +export class ShippingTaxRate { + @PrimaryColumn() + shipping_option_id: string + + @PrimaryColumn() + rate_id: string + + @ManyToOne(() => ShippingOption, { onDelete: "CASCADE" }) + @JoinColumn({ name: "shipping_option_id" }) + shipping_option?: ShippingOption + + @ManyToOne(() => TaxRate, { onDelete: "CASCADE" }) + @JoinColumn({ name: "rate_id" }) + tax_rate?: TaxRate + + @CreateDateColumn({ type: resolveDbType("timestamptz") }) + created_at: Date + + @UpdateDateColumn({ type: resolveDbType("timestamptz") }) + updated_at: Date + + @DbAwareColumn({ type: "jsonb", nullable: true }) + metadata: any +} + +/** + * @schema shipping_tax_rate + * title: "Shipping Tax Rate" + * description: "Associates a tax rate with a shipping option to indicate that the shipping option is taxed in a certain way" + * x-resourceId: shipping_tax_rate + * properties: + * shipping_option_id: + * description: "The id of the Shipping Option" + * type: string + * rate_id: + * description: "The id of the Tax Rate" + * type: string + * created_at: + * description: "The date with timezone at which the resource was created." + * type: string + * format: date-time + * updated_at: + * description: "The date with timezone at which the resource was last updated." + * type: string + * format: date-time + * deleted_at: + * description: "The date with timezone at which the resource was deleted." + * type: string + * format: date-time + * metadata: + * description: "An optional key-value map with additional information." + * type: object + */ diff --git a/packages/medusa/src/models/swap.ts b/packages/medusa/src/models/swap.ts index cb44a825cd..e976765671 100644 --- a/packages/medusa/src/models/swap.ts +++ b/packages/medusa/src/models/swap.ts @@ -63,35 +63,35 @@ export class Swap { @ManyToOne( () => Order, - o => o.swaps + (o) => o.swaps ) @JoinColumn({ name: "order_id" }) order: Order @OneToMany( () => LineItem, - item => item.swap, + (item) => item.swap, { cascade: ["insert"] } ) - additional_items: LineItem + additional_items: LineItem[] @OneToOne( () => Return, - ret => ret.swap, + (ret) => ret.swap, { cascade: ["insert"] } ) return_order: Return @OneToMany( () => Fulfillment, - fulfillment => fulfillment.swap, + (fulfillment) => fulfillment.swap, { cascade: ["insert"] } ) fulfillments: Fulfillment[] @OneToOne( () => Payment, - p => p.swap, + (p) => p.swap, { cascade: ["insert"] } ) payment: Payment @@ -108,7 +108,7 @@ export class Swap { @OneToMany( () => ShippingMethod, - method => method.swap, + (method) => method.swap, { cascade: ["insert"] } ) shipping_methods: ShippingMethod[] diff --git a/packages/medusa/src/models/tax-line.ts b/packages/medusa/src/models/tax-line.ts new file mode 100644 index 0000000000..9c5356c8d8 --- /dev/null +++ b/packages/medusa/src/models/tax-line.ts @@ -0,0 +1,61 @@ +import { + CreateDateColumn, + UpdateDateColumn, + Column, + PrimaryColumn, +} from "typeorm" +import { resolveDbType, DbAwareColumn } from "../utils/db-aware-column" + +export class TaxLine { + @PrimaryColumn() + id: string + + @Column({ type: "real" }) + rate: number + + @Column() + name: string + + @Column({ type: "varchar", nullable: true }) + code: string | null + + @CreateDateColumn({ type: resolveDbType("timestamptz") }) + created_at: Date + + @UpdateDateColumn({ type: resolveDbType("timestamptz") }) + updated_at: Date + + @DbAwareColumn({ type: "jsonb", nullable: true }) + metadata: any +} + +/** + * @schema tax_line + * title: "Tax Line" + * description: "Line item that specifies an amount of tax to add to a line item." + * x-resourceId: tax_line + * properties: + * id: + * description: "The id of the Tax Line. This value will be prefixed by `tl_`." + * type: string + * code: + * description: "A code to identify the tax type by" + * type: string + * name: + * description: "A human friendly name for the tax" + * type: string + * rate: + * description: "The numeric rate to charge tax by" + * type: number + * created_at: + * description: "The date with timezone at which the resource was created." + * type: string + * format: date-time + * updated_at: + * description: "The date with timezone at which the resource was last updated." + * type: string + * format: date-time + * metadata: + * description: "An optional key-value map with additional information." + * type: object + */ diff --git a/packages/medusa/src/models/tax-provider.ts b/packages/medusa/src/models/tax-provider.ts new file mode 100644 index 0000000000..c6c48c2307 --- /dev/null +++ b/packages/medusa/src/models/tax-provider.ts @@ -0,0 +1,24 @@ +import { Entity, Column, PrimaryColumn } from "typeorm" + +@Entity() +export class TaxProvider { + @PrimaryColumn() + id: string + + @Column({ default: true }) + is_installed: boolean +} + +/** + * @schema tax_provider + * title: "Tax Provider" + * description: "The tax service used to calculate taxes" + * x-resourceId: tax_provider + * properties: + * id: + * description: "The id of the tax provider as given by the plugin." + * type: string + * is_installed: + * description: "Whether the plugin is installed in the current version. Plugins that are no longer installed are not deleted by will have this field set to `false`." + * type: boolean + */ diff --git a/packages/medusa/src/models/tax-rate.ts b/packages/medusa/src/models/tax-rate.ts new file mode 100644 index 0000000000..953cb00b75 --- /dev/null +++ b/packages/medusa/src/models/tax-rate.ts @@ -0,0 +1,141 @@ +import { + Entity, + BeforeInsert, + CreateDateColumn, + UpdateDateColumn, + Column, + PrimaryColumn, + ManyToOne, + ManyToMany, + JoinColumn, + JoinTable, +} from "typeorm" +import { ulid } from "ulid" +import { resolveDbType, DbAwareColumn } from "../utils/db-aware-column" + +import { Region } from "./region" +import { Product } from "./product" +import { ProductType } from "./product-type" +import { ShippingOption } from "./shipping-option" + +@Entity() +export class TaxRate { + @PrimaryColumn() + id: string + + @Column({ type: "real", nullable: true }) + rate: number | null + + @Column({ type: "varchar", nullable: true }) + code: string | null + + @Column() + name: string + + @Column() + region_id: string + + @ManyToOne(() => Region) + @JoinColumn({ name: "region_id" }) + region: Region + + @CreateDateColumn({ type: resolveDbType("timestamptz") }) + created_at: Date + + @UpdateDateColumn({ type: resolveDbType("timestamptz") }) + updated_at: Date + + @DbAwareColumn({ type: "jsonb", nullable: true }) + metadata: any + + @ManyToMany(() => Product) + @JoinTable({ + name: "product_tax_rate", + joinColumn: { + name: "rate_id", + referencedColumnName: "id", + }, + inverseJoinColumn: { + name: "product_id", + referencedColumnName: "id", + }, + }) + products: Product[] + + @ManyToMany(() => ProductType) + @JoinTable({ + name: "product_type_tax_rate", + joinColumn: { + name: "rate_id", + referencedColumnName: "id", + }, + inverseJoinColumn: { + name: "product_type_id", + referencedColumnName: "id", + }, + }) + product_types: ProductType[] + + @ManyToMany(() => ShippingOption) + @JoinTable({ + name: "shipping_tax_rate", + joinColumn: { + name: "rate_id", + referencedColumnName: "id", + }, + inverseJoinColumn: { + name: "shipping_option_id", + referencedColumnName: "id", + }, + }) + shipping_options: ShippingOption[] + + // TODO: consider custom DTO instead + product_count?: number + product_type_count?: number + shipping_option_count?: number + + @BeforeInsert() + private beforeInsert() { + if (this.id) return + const id = ulid() + this.id = `txr_${id}` + } +} + +/** + * @schema tax_rate + * title: "Tax Rate" + * description: "A Tax Rate can be used to associate a certain rate to charge on products within a given Region" + * x-resourceId: line_item + * properties: + * id: + * description: "The id of the Tax Rate. This value will be prefixed by `txr_`." + * type: string + * rate: + * description: "The numeric rate to charge" + * type: number + * code: + * description: "A code to identify the tax type by" + * type: string + * name: + * description: "A human friendly name for the tax" + * type: string + * region_id: + * description: "The id of the Region that the rate belongs to" + * type: string + * created_at: + * description: "The date with timezone at which the resource was created." + * type: string + * format: date-time + * updated_at: + * description: "The date with timezone at which the resource was last updated." + * type: string + * format: date-time + * metadata: + * description: "An optional key-value map with additional information." + * type: object + * refundable: + * description: "The amount that can be refunded from the given Line Item. Takes taxes and discounts into consideration." + * type: integer + */ diff --git a/packages/medusa/src/repositories/line-item-tax-line.ts b/packages/medusa/src/repositories/line-item-tax-line.ts new file mode 100644 index 0000000000..96da16e3ff --- /dev/null +++ b/packages/medusa/src/repositories/line-item-tax-line.ts @@ -0,0 +1,5 @@ +import { EntityRepository, Repository } from "typeorm" +import { LineItemTaxLine } from "../models/line-item-tax-line" + +@EntityRepository(LineItemTaxLine) +export class LineItemTaxLineRepository extends Repository {} diff --git a/packages/medusa/src/repositories/line-item.ts b/packages/medusa/src/repositories/line-item.ts index 01e3e9221e..5ef3b96c6b 100644 --- a/packages/medusa/src/repositories/line-item.ts +++ b/packages/medusa/src/repositories/line-item.ts @@ -1,5 +1,30 @@ import { EntityRepository, Repository } from "typeorm" import { LineItem } from "../models/line-item" +import { ReturnItem } from "../models/return-item" @EntityRepository(LineItem) -export class LineItemRepository extends Repository {} +export class LineItemRepository extends Repository { + /** + * Finds line items that are to be returned as part of the Return represented + * by `returnId`. The function joins the associated ReturnItem and the + * LineItem's TaxLines. + * @param returnId - the id of the Return to get LineItems by + * @return the LineItems associated with the Return with its ReturnItem joined + * and mapped to `return_item`. + */ + async findByReturn( + returnId: string + ): Promise<(LineItem & { return_item: ReturnItem })[]> { + const qb = this.createQueryBuilder("li") + .leftJoinAndSelect(`li.tax_lines`, "tax_lines") + .leftJoinAndMapOne( + `li.return_item`, + ReturnItem, + `ri`, + `ri.item_id = li.id` + ) + .where(`ri.return_id = :returnId`, { returnId }) + + return (await qb.getMany()) as (LineItem & { return_item: ReturnItem })[] + } +} diff --git a/packages/medusa/src/repositories/product-tax-rate.ts b/packages/medusa/src/repositories/product-tax-rate.ts new file mode 100644 index 0000000000..db166fb5b6 --- /dev/null +++ b/packages/medusa/src/repositories/product-tax-rate.ts @@ -0,0 +1,5 @@ +import { EntityRepository, Repository } from "typeorm" +import { ProductTaxRate } from "../models/product-tax-rate" + +@EntityRepository(ProductTaxRate) +export class ProductTaxRateRepository extends Repository {} diff --git a/packages/medusa/src/repositories/shipping-method-tax-line.ts b/packages/medusa/src/repositories/shipping-method-tax-line.ts new file mode 100644 index 0000000000..6fb3deb172 --- /dev/null +++ b/packages/medusa/src/repositories/shipping-method-tax-line.ts @@ -0,0 +1,5 @@ +import { EntityRepository, Repository } from "typeorm" +import { ShippingMethodTaxLine } from "../models/shipping-method-tax-line" + +@EntityRepository(ShippingMethodTaxLine) +export class ShippingMethodTaxLineRepository extends Repository {} diff --git a/packages/medusa/src/repositories/shipping-tax-rate.ts b/packages/medusa/src/repositories/shipping-tax-rate.ts new file mode 100644 index 0000000000..2a68b2a451 --- /dev/null +++ b/packages/medusa/src/repositories/shipping-tax-rate.ts @@ -0,0 +1,5 @@ +import { EntityRepository, Repository } from "typeorm" +import { ShippingTaxRate } from "../models/shipping-tax-rate" + +@EntityRepository(ShippingTaxRate) +export class ShippingTaxRateRepository extends Repository {} diff --git a/packages/medusa/src/repositories/tax-provider.ts b/packages/medusa/src/repositories/tax-provider.ts new file mode 100644 index 0000000000..24c963f429 --- /dev/null +++ b/packages/medusa/src/repositories/tax-provider.ts @@ -0,0 +1,5 @@ +import { EntityRepository, Repository } from "typeorm" +import { TaxProvider } from "../models/tax-provider" + +@EntityRepository(TaxProvider) +export class TaxProviderRepository extends Repository {} diff --git a/packages/medusa/src/repositories/tax-rate.ts b/packages/medusa/src/repositories/tax-rate.ts new file mode 100644 index 0000000000..72a897d759 --- /dev/null +++ b/packages/medusa/src/repositories/tax-rate.ts @@ -0,0 +1,274 @@ +import { unionBy } from "lodash" +import { + In, + Not, + DeleteResult, + SelectQueryBuilder, + EntityRepository, + FindManyOptions, + FindOptionsUtils, + Repository, +} from "typeorm" +import { TaxRate } from "../models/tax-rate" +import { ProductTaxRate } from "../models/product-tax-rate" +import { ProductTypeTaxRate } from "../models/product-type-tax-rate" +import { ShippingTaxRate } from "../models/shipping-tax-rate" +import { Product } from "../models/product" +import { ShippingMethod } from "../models/shipping-method" +import { TaxRateListByConfig } from "../types/tax-rate" + +const resolveableFields = [ + "product_count", + "product_type_count", + "shipping_option_count", +] + +@EntityRepository(TaxRate) +export class TaxRateRepository extends Repository { + getFindQueryBuilder(findOptions: FindManyOptions) { + let qb = this.createQueryBuilder("tr") + const cleanOptions = findOptions + + const resolverFields: string[] = [] + if (typeof findOptions.select !== "undefined") { + let selectableCols: (keyof TaxRate)[] = [] + for (const k of findOptions.select) { + if (!resolveableFields.includes(k)) { + selectableCols.push(k) + } else { + resolverFields.push(k) + } + } + cleanOptions.select = selectableCols + } + + FindOptionsUtils.applyFindManyOptionsOrConditionsToQueryBuilder( + qb, + cleanOptions + ) + + if (resolverFields.length > 0) { + this.applyResolutionsToQueryBuilder(qb, resolverFields) + } + + return qb + } + + async findWithResolution(findOptions: FindManyOptions) { + const qb = this.getFindQueryBuilder(findOptions) + return await qb.getMany() + } + + async findOneWithResolution(findOptions: FindManyOptions) { + const qb = this.getFindQueryBuilder(findOptions) + return await qb.getOne() + } + + async findAndCountWithResolution(findOptions: FindManyOptions) { + const qb = this.getFindQueryBuilder(findOptions) + return await qb.getManyAndCount() + } + + applyResolutionsToQueryBuilder( + qb: SelectQueryBuilder, + resolverFields: string[] + ): SelectQueryBuilder { + for (const k of resolverFields) { + switch (k) { + case "product_count": + qb.loadRelationCountAndMap( + `${qb.alias}.product_count`, + `${qb.alias}.products` + ) + break + case "product_type_count": + qb.loadRelationCountAndMap( + `${qb.alias}.product_type_count`, + `${qb.alias}.product_types` + ) + break + case "shipping_option_count": + qb.loadRelationCountAndMap( + `${qb.alias}.shipping_option_count`, + `${qb.alias}.shipping_options` + ) + break + default: + break + } + } + + return qb + } + + async removeFromProduct( + id: string, + productIds: string[] + ): Promise { + return await this.createQueryBuilder() + .delete() + .from(ProductTaxRate) + .where({ rate_id: id, product_id: In(productIds) }) + .execute() + } + + async addToProduct( + id: string, + productIds: string[], + overrideExisting: boolean = false + ): Promise { + const toInsert = productIds.map((pId) => ({ rate_id: id, product_id: pId })) + const insertResult = await this.createQueryBuilder() + .insert() + .orIgnore(true) + .into(ProductTaxRate) + .values(toInsert) + .execute() + + if (overrideExisting) { + await this.createQueryBuilder() + .delete() + .from(ProductTaxRate) + .where({ rate_id: id, product_id: Not(In(productIds)) }) + .execute() + } + + return await this.manager + .createQueryBuilder(ProductTaxRate, "ptr") + .select() + .where(insertResult.identifiers) + .getMany() + } + + async removeFromProductType( + id: string, + productTypeIds: string[] + ): Promise { + return await this.createQueryBuilder() + .delete() + .from(ProductTypeTaxRate) + .where({ rate_id: id, product_type_id: In(productTypeIds) }) + .execute() + } + + async addToProductType( + id: string, + productTypeIds: string[], + overrideExisting: boolean = false + ): Promise { + const toInsert = productTypeIds.map((pId) => ({ + rate_id: id, + product_type_id: pId, + })) + const insertResult = await this.createQueryBuilder() + .insert() + .orIgnore(true) + .into(ProductTypeTaxRate) + .values(toInsert) + .execute() + + if (overrideExisting) { + await this.createQueryBuilder() + .delete() + .from(ProductTypeTaxRate) + .where({ rate_id: id, product_type_id: Not(In(productTypeIds)) }) + .execute() + } + + return await this.manager + .createQueryBuilder(ProductTypeTaxRate, "ptr") + .select() + .where(insertResult.identifiers) + .getMany() + } + + async removeFromShippingOption( + id: string, + optionIds: string[] + ): Promise { + return await this.createQueryBuilder() + .delete() + .from(ShippingTaxRate) + .where({ rate_id: id, shipping_option_id: In(optionIds) }) + .execute() + } + + async addToShippingOption( + id: string, + optionIds: string[], + overrideExisting: boolean = false + ): Promise { + const toInsert = optionIds.map((pId) => ({ + rate_id: id, + shipping_option_id: pId, + })) + const insertResult = await this.createQueryBuilder() + .insert() + .orIgnore(true) + .into(ShippingTaxRate) + .values(toInsert) + .execute() + + if (overrideExisting) { + await this.createQueryBuilder() + .delete() + .from(ShippingTaxRate) + .where({ rate_id: id, shipping_option_id: Not(In(optionIds)) }) + .execute() + } + + return await this.manager + .createQueryBuilder(ShippingTaxRate, "str") + .select() + .where(insertResult.identifiers) + .getMany() + } + + async listByProduct(productId: string, config: TaxRateListByConfig) { + let productRates = this.createQueryBuilder("txr") + .leftJoin(ProductTaxRate, "ptr", "ptr.rate_id = txr.id") + .leftJoin(Product, "prod", "prod.id = ptr.product_id") + .where("prod.id = :productId", { productId }) + + let typeRates = this.createQueryBuilder("txr") + .leftJoin(ProductTypeTaxRate, "pttr", "pttr.rate_id = txr.id") + .leftJoin(Product, "prod", "prod.type_id = pttr.product_type_id") + .where("prod.id = :productId", { productId }) + + if (typeof config.region_id !== "undefined") { + productRates.andWhere("txr.region_id = :regionId", { + regionId: config.region_id, + }) + typeRates.andWhere("txr.region_id = :regionId", { + regionId: config.region_id, + }) + } + + const results = await Promise.all([ + productRates.getMany(), + typeRates.getMany(), + ]) + + // Only return unique rates by joining the two arrays from typeRates and + // productRates matching based on the id + return unionBy(...results, (txr) => txr.id) + } + + async listByShippingOption(optionId: string, config: TaxRateListByConfig) { + let rates = this.createQueryBuilder("txr") + .leftJoin(ShippingTaxRate, "ptr", "ptr.rate_id = txr.id") + .leftJoin( + ShippingMethod, + "sm", + "sm.shipping_option_id = ptr.shipping_option_id" + ) + .where("sm.shipping_option_id = :optionId", { optionId }) + + if (typeof config.region_id !== "undefined") { + rates.andWhere("txr.region_id = :regionId", { + regionId: config.region_id, + }) + } + return await rates.getMany() + } +} diff --git a/packages/medusa/src/services/__mocks__/shipping-option.js b/packages/medusa/src/services/__mocks__/shipping-option.js index d20a20314c..447f2e66c3 100644 --- a/packages/medusa/src/services/__mocks__/shipping-option.js +++ b/packages/medusa/src/services/__mocks__/shipping-option.js @@ -67,7 +67,7 @@ export const shippingOptions = { } export const ShippingOptionServiceMock = { - retrieve: jest.fn().mockImplementation(optionId => { + retrieve: jest.fn().mockImplementation((optionId) => { if (optionId === IdMap.getId("return-shipping")) { return Promise.resolve(shippingOptions.returnShipping) } @@ -86,9 +86,21 @@ export const ShippingOptionServiceMock = { return Promise.resolve(undefined) }), update: jest.fn().mockReturnValue(Promise.resolve()), - list: jest.fn().mockImplementation(data => { + listAndCount: jest.fn().mockImplementation((data) => { + if (data.region_id === IdMap.getId("region-france")) { + return Promise.resolve([[shippingOptions.franceShipping], 1]) + } + if (data.region_id === IdMap.getId("testRegion")) { + return Promise.resolve([ + [shippingOptions.freeShipping, shippingOptions.expensiveShipping], + 2, + ]) + } + return Promise.resolve([[], 0]) + }), + list: jest.fn().mockImplementation((data) => { if (!data) { - return Promise.resolve() + return Promise.resolve([]) } if (data.region_id === IdMap.getId("region-france")) { return Promise.resolve([shippingOptions.franceShipping]) @@ -100,7 +112,7 @@ export const ShippingOptionServiceMock = { ]) } }), - create: jest.fn().mockImplementation(data => { + create: jest.fn().mockImplementation((data) => { return Promise.resolve(data) }), validateFulfillmentData: jest diff --git a/packages/medusa/src/services/__tests__/cart.js b/packages/medusa/src/services/__tests__/cart.js index 536e5d88e1..edaa677af1 100644 --- a/packages/medusa/src/services/__tests__/cart.js +++ b/packages/medusa/src/services/__tests__/cart.js @@ -655,6 +655,8 @@ describe("CartService", () => { "discounts.rule", "discounts.rule.valid_for", "discounts.regions", + "items.tax_lines", + "region.tax_rates", ], { where: { id: "withpays" }, diff --git a/packages/medusa/src/services/__tests__/claim.js b/packages/medusa/src/services/__tests__/claim.js index 5385b14599..d008037bbe 100644 --- a/packages/medusa/src/services/__tests__/claim.js +++ b/packages/medusa/src/services/__tests__/claim.js @@ -5,13 +5,14 @@ import { InventoryServiceMock } from "../__mocks__/inventory" const withTransactionMock = jest.fn() const eventBusService = { emit: jest.fn(), - withTransaction: function() { + withTransaction: function () { withTransactionMock("eventBus") return this }, } const totalsService = { + getCalculationContext: jest.fn(() => {}), getRefundTotal: jest.fn(() => 1000), } @@ -54,12 +55,20 @@ describe("ClaimService", () => { } const claimRepo = MockRepository({ - create: d => ({ id: "claim_134", ...d }), + create: (d) => ({ id: "claim_134", ...d }), }) + const taxProviderService = { + createTaxLines: jest.fn(), + withTransaction: function () { + withTransactionMock("return") + return this + }, + } + const returnService = { create: jest.fn(), - withTransaction: function() { + withTransaction: function () { withTransactionMock("return") return this }, @@ -68,7 +77,8 @@ describe("ClaimService", () => { const lineItemService = { generate: jest.fn((d, _, q) => ({ variant_id: d, quantity: q })), retrieve: () => Promise.resolve({}), - withTransaction: function() { + list: () => Promise.resolve([{}]), + withTransaction: function () { withTransactionMock("lineItem") return this }, @@ -76,7 +86,7 @@ describe("ClaimService", () => { const inventoryService = { ...InventoryServiceMock, - withTransaction: function() { + withTransaction: function () { withTransactionMock("inventory") return this }, @@ -84,7 +94,7 @@ describe("ClaimService", () => { const claimItemService = { create: jest.fn(), - withTransaction: function() { + withTransaction: function () { withTransactionMock("claimItem") return this }, @@ -93,6 +103,7 @@ describe("ClaimService", () => { const claimService = new ClaimService({ manager: MockManager, claimRepository: claimRepo, + taxProviderService, totalsService, returnService, lineItemService, @@ -303,7 +314,7 @@ describe("ClaimService", () => { createFulfillment: jest.fn((_, items) => Promise.resolve([{ id: "ful", items }]) ), - withTransaction: function() { + withTransaction: function () { withTransactionMock("fulfillment") return this }, @@ -339,7 +350,7 @@ describe("ClaimService", () => { const lineItemService = { update: jest.fn(), retrieve: () => Promise.resolve({}), - withTransaction: function() { + withTransaction: function () { withTransactionMock("lineItem") return this }, @@ -440,11 +451,11 @@ describe("ClaimService", () => { describe("cancelFulfillment", () => { const claimRepo = MockRepository({ findOne: () => Promise.resolve({}), - save: f => Promise.resolve(f), + save: (f) => Promise.resolve(f), }) const fulfillmentService = { - cancelFulfillment: jest.fn().mockImplementation(f => { + cancelFulfillment: jest.fn().mockImplementation((f) => { switch (f) { case IdMap.getId("no-claim"): return Promise.resolve({}) @@ -454,7 +465,7 @@ describe("ClaimService", () => { }) } }), - withTransaction: function() { + withTransaction: function () { return this }, } @@ -519,7 +530,7 @@ describe("ClaimService", () => { ], }) }), - withTransaction: function() { + withTransaction: function () { withTransactionMock("fulfillment") return this }, @@ -528,7 +539,7 @@ describe("ClaimService", () => { const lineItemService = { update: jest.fn(), retrieve: () => Promise.resolve({}), - withTransaction: function() { + withTransaction: function () { withTransactionMock("lineItem") return this }, @@ -623,7 +634,7 @@ describe("ClaimService", () => { describe("cancel", () => { const fulfillmentService = { cancelFulfillment: jest.fn(), - withTransaction: function() { + withTransaction: function () { withTransactionMock("fulfillment") return this }, @@ -631,7 +642,7 @@ describe("ClaimService", () => { const returnService = { cancel: jest.fn(), - withTransaction: function() { + withTransaction: function () { withTransactionMock("return") return this }, @@ -642,7 +653,7 @@ describe("ClaimService", () => { const fulfillment = { id: "ful_21", canceled_at: now } const claimRepo = MockRepository({ - findOne: q => { + findOne: (q) => { const claim = { return_order: { ...ret_order }, fulfillments: [{ ...fulfillment }], diff --git a/packages/medusa/src/services/__tests__/order.js b/packages/medusa/src/services/__tests__/order.js index 72555220f9..425c42cf30 100644 --- a/packages/medusa/src/services/__tests__/order.js +++ b/packages/medusa/src/services/__tests__/order.js @@ -5,35 +5,35 @@ import { InventoryServiceMock } from "../__mocks__/inventory" describe("OrderService", () => { const totalsService = { getLineItemRefund: () => {}, - getTotal: o => { + getTotal: (o) => { return o.total || 0 }, - getRefundedTotal: o => { + getRefundedTotal: (o) => { return o.refunded_total || 0 }, - getShippingTotal: o => { + getShippingTotal: (o) => { return o.shipping_total || 0 }, - getGiftCardTotal: o => { + getGiftCardTotal: (o) => { return o.gift_card_total || 0 }, - getDiscountTotal: o => { + getDiscountTotal: (o) => { return o.discount_total || 0 }, - getTaxTotal: o => { + getTaxTotal: (o) => { return o.tax_total || 0 }, - getSubtotal: o => { + getSubtotal: (o) => { return o.subtotal || 0 }, - getPaidTotal: o => { + getPaidTotal: (o) => { return o.paid_total || 0 }, } const eventBusService = { emit: jest.fn(), - withTransaction: function() { + withTransaction: function () { return this }, } @@ -43,7 +43,7 @@ describe("OrderService", () => { } describe("create", () => { - const orderRepo = MockRepository({ create: f => f }) + const orderRepo = MockRepository({ create: (f) => f }) const orderService = new OrderService({ manager: MockManager, orderRepository: orderRepo, @@ -73,37 +73,37 @@ describe("OrderService", () => { describe("createFromCart", () => { const orderRepo = MockRepository({ - create: p => p, - save: p => ({ ...p, id: "id" }), + create: (p) => p, + save: (p) => ({ ...p, id: "id" }), }) const lineItemService = { update: jest.fn(), - withTransaction: function() { + withTransaction: function () { return this }, } const shippingOptionService = { updateShippingMethod: jest.fn(), - withTransaction: function() { + withTransaction: function () { return this }, } const giftCardService = { update: jest.fn(), createTransaction: jest.fn(), - withTransaction: function() { + withTransaction: function () { return this }, } const paymentProviderService = { - getStatus: payment => { + getStatus: (payment) => { return Promise.resolve(payment.status || "authorized") }, updatePayment: jest.fn(), - cancelPayment: jest.fn().mockImplementation(payment => { + cancelPayment: jest.fn().mockImplementation((payment) => { return Promise.resolve({ ...payment, status: "cancelled" }) }), - withTransaction: function() { + withTransaction: function () { return this }, } @@ -113,7 +113,7 @@ describe("OrderService", () => { total: 0, } const cartService = { - retrieve: jest.fn().mockImplementation(query => { + retrieve: jest.fn().mockImplementation((query) => { if (query === "empty") { return Promise.resolve(emptyCart) } @@ -142,7 +142,7 @@ describe("OrderService", () => { total: 100, }) }), - withTransaction: function() { + withTransaction: function () { return this }, } @@ -211,14 +211,12 @@ describe("OrderService", () => { email: cart.email, customer_id: cart.customer_id, shipping_methods: cart.shipping_methods, - customer_id: "cus_1234", discounts: cart.discounts, billing_address_id: cart.billing_address_id, shipping_address_id: cart.shipping_address_id, region_id: cart.region_id, currency_code: "eur", cart_id: "cart_id", - tax_rate: 25, gift_cards: [], metadata: {}, } @@ -316,14 +314,12 @@ describe("OrderService", () => { email: cart.email, customer_id: cart.customer_id, shipping_methods: cart.shipping_methods, - customer_id: "cus_1234", discounts: cart.discounts, billing_address_id: cart.billing_address_id, shipping_address_id: cart.shipping_address_id, region_id: cart.region_id, currency_code: "eur", cart_id: "cart_id", - tax_rate: 25, gift_cards: [ { id: "gid", @@ -403,7 +399,6 @@ describe("OrderService", () => { email: cart.email, customer_id: cart.customer_id, shipping_methods: cart.shipping_methods, - customer_id: "cus_1234", discounts: cart.discounts, billing_address_id: cart.billing_address_id, shipping_address_id: cart.shipping_address_id, @@ -411,7 +406,6 @@ describe("OrderService", () => { region_id: cart.region_id, currency_code: "eur", cart_id: "cart_id", - tax_rate: 25, metadata: {}, } expect(orderRepo.create).toHaveBeenCalledTimes(1) @@ -471,7 +465,7 @@ describe("OrderService", () => { describe("retrieve", () => { const orderRepo = MockRepository({ - findOneWithRelations: q => { + findOneWithRelations: (q) => { return Promise.resolve({}) }, }) @@ -496,7 +490,7 @@ describe("OrderService", () => { describe("retrieveByCartId", () => { const orderRepo = MockRepository({ - findOne: q => { + findOne: (q) => { return Promise.resolve({}) }, }) @@ -640,14 +634,14 @@ describe("OrderService", () => { const fulfillmentService = { cancelFulfillment: jest.fn(), - withTransaction: function() { + withTransaction: function () { return this }, } const paymentProviderService = { cancelPayment: jest.fn(), - withTransaction: function() { + withTransaction: function () { return this }, } @@ -668,10 +662,7 @@ describe("OrderService", () => { it("calls order model functions", async () => { try { - const order = await orderService.retrieve( - IdMap.getId("not-fulfilled-order") - ) - console.warn(order) + await orderService.retrieve(IdMap.getId("not-fulfilled-order")) await orderService.cancel(IdMap.getId("not-fulfilled-order")) } catch (e) { console.warn(e) @@ -696,6 +687,7 @@ describe("OrderService", () => { expect(orderRepo.save).toHaveBeenCalledWith({ fulfillment_status: "canceled", payment_status: "canceled", + canceled_at: expect.any(Date), status: "canceled", fulfillments: [{ id: "fulfillment_test", canceled_at: now }], payments: [{ id: "payment_test" }], @@ -741,12 +733,12 @@ describe("OrderService", () => { const paymentProviderService = { capturePayment: jest .fn() - .mockImplementation(p => + .mockImplementation((p) => p.id === "payment_fail" ? Promise.reject() : Promise.resolve({ ...p, captured_at: "notnull" }) ), - withTransaction: function() { + withTransaction: function () { return this }, } @@ -851,7 +843,7 @@ describe("OrderService", () => { const lineItemService = { update: jest.fn(), - withTransaction: function() { + withTransaction: function () { return this }, } @@ -864,7 +856,7 @@ describe("OrderService", () => { }, ]) }), - withTransaction: function() { + withTransaction: function () { return this }, } @@ -1017,11 +1009,11 @@ describe("OrderService", () => { describe("cancelFulfillment", () => { const orderRepo = MockRepository({ findOneWithRelations: () => Promise.resolve({}), - save: f => Promise.resolve(f), + save: (f) => Promise.resolve(f), }) const fulfillmentService = { - cancelFulfillment: jest.fn().mockImplementation(f => { + cancelFulfillment: jest.fn().mockImplementation((f) => { switch (f) { case IdMap.getId("no-order"): return Promise.resolve({}) @@ -1031,7 +1023,7 @@ describe("OrderService", () => { }) } }), - withTransaction: function() { + withTransaction: function () { return this }, } @@ -1097,10 +1089,10 @@ describe("OrderService", () => { const paymentProviderService = { refundPayment: jest .fn() - .mockImplementation(p => + .mockImplementation((p) => p.id === "payment_fail" ? Promise.reject() : Promise.resolve() ), - withTransaction: function() { + withTransaction: function () { return this }, } @@ -1176,7 +1168,7 @@ describe("OrderService", () => { return Promise.resolve({ id: IdMap.getId("order") }) } }, - save: jest.fn().mockImplementation(f => f), + save: jest.fn().mockImplementation((f) => f), }) const eventBus = { @@ -1228,7 +1220,7 @@ describe("OrderService", () => { }) } }, - save: jest.fn().mockImplementation(f => f), + save: jest.fn().mockImplementation((f) => f), }) const optionService = { @@ -1241,7 +1233,7 @@ describe("OrderService", () => { .fn() .mockImplementation(() => Promise.resolve({})), - withTransaction: function() { + withTransaction: function () { return this }, } @@ -1375,7 +1367,7 @@ describe("OrderService", () => { const lineItemService = { update: jest.fn(), - withTransaction: function() { + withTransaction: function () { return this }, } @@ -1398,7 +1390,7 @@ describe("OrderService", () => { ], }) }), - withTransaction: function() { + withTransaction: function () { return this }, } @@ -1425,9 +1417,7 @@ describe("OrderService", () => { ) expect(fulfillmentService.createShipment).toHaveBeenCalledTimes(1) - expect( - fulfillmentService.createShipment - ).toHaveBeenCalledWith( + expect(fulfillmentService.createShipment).toHaveBeenCalledWith( IdMap.getId("fulfillment"), [{ tracking_number: "1234" }, { tracking_number: "2345" }], { metadata: undefined, no_notification: true } @@ -1518,8 +1508,8 @@ describe("OrderService", () => { const paymentProviderService = { refundPayment: jest .fn() - .mockImplementation(p => Promise.resolve({ id: "ref" })), - withTransaction: function() { + .mockImplementation((p) => Promise.resolve({ id: "ref" })), + withTransaction: function () { return this }, } diff --git a/packages/medusa/src/services/__tests__/swap.js b/packages/medusa/src/services/__tests__/swap.js index 54fa1c44e1..8d276e30ab 100644 --- a/packages/medusa/src/services/__tests__/swap.js +++ b/packages/medusa/src/services/__tests__/swap.js @@ -160,6 +160,11 @@ describe("SwapService", () => { const cartService = { create: jest.fn().mockReturnValue(Promise.resolve({ id: "cart" })), + retrieve: jest + .fn() + .mockReturnValue( + Promise.resolve({ id: "cart", items: [{ id: "test-item" }] }) + ), update: jest.fn().mockReturnValue(Promise.resolve()), withTransaction: function () { return this @@ -173,7 +178,7 @@ describe("SwapService", () => { const customShippingOptionService = { create: jest.fn().mockReturnValue(Promise.resolve({ id: "cso-test" })), update: jest.fn().mockReturnValue(Promise.resolve()), - withTransaction: function() { + withTransaction: function () { return this }, } @@ -182,6 +187,7 @@ describe("SwapService", () => { create: jest.fn().mockImplementation((d) => Promise.resolve(d)), update: jest.fn().mockImplementation((d) => Promise.resolve(d)), retrieve: () => Promise.resolve({}), + createReturnLines: jest.fn(() => Promise.resolve()), withTransaction: function () { return this }, @@ -216,12 +222,19 @@ describe("SwapService", () => { "return_order", "return_order.items", "return_order.shipping_method", + "return_order.shipping_method.tax_lines", ], { where: { id: IdMap.getId("swap-1") }, } ) + expect(lineItemService.createReturnLines).toHaveBeenCalledTimes(1) + expect(lineItemService.createReturnLines).toHaveBeenCalledWith( + expect.any(String), + "cart" + ) + expect(cartService.create).toHaveBeenCalledTimes(1) expect(cartService.create).toHaveBeenCalledWith({ email: testOrder.email, @@ -404,126 +417,6 @@ describe("SwapService", () => { }) }) - describe("receiveReturn", () => { - beforeEach(() => { - jest.clearAllMocks() - }) - - describe("success", () => { - const returnService = { - receiveReturn: jest - .fn() - .mockReturnValue(Promise.resolve({ test: "received" })), - withTransaction: function () { - return this - }, - } - - const existing = { - order_id: IdMap.getId("test"), - return_id: IdMap.getId("test"), - return_order: { - id: IdMap.getId("return-swap"), - test: "notreceived", - refund_amount: 11, - }, - other: "data", - } - - const swapRepo = MockRepository({ - findOneWithRelations: () => Promise.resolve(existing), - }) - const swapService = new SwapService({ - manager: MockManager, - eventBusService, - swapRepository: swapRepo, - returnService, - }) - - it("calls register return and updates return value", async () => { - await swapService.receiveReturn(IdMap.getId("swap"), [ - { item_id: IdMap.getId("1234"), quantity: 1 }, - ]) - - expect(returnService.receiveReturn).toHaveBeenCalledTimes(1) - expect(returnService.receiveReturn).toHaveBeenCalledWith( - IdMap.getId("return-swap"), - [{ item_id: IdMap.getId("1234"), quantity: 1 }], - undefined, - false - ) - }) - }) - - describe("failure", () => { - const returnService = { - receiveReturn: jest - .fn() - .mockReturnValue(Promise.resolve({ status: "requires_action" })), - withTransaction: function () { - return this - }, - } - - const existing = { - order_id: IdMap.getId("test"), - return_id: IdMap.getId("return-swap"), - return_order_id: IdMap.getId("return-swap"), - return_order: { id: IdMap.getId("return-swap") }, - other: "data", - } - - const swapRepo = MockRepository({ - findOneWithRelations: (rels, q) => { - switch (q.where.id) { - case IdMap.getId("canceled"): - return Promise.resolve({ canceled_at: new Date() }) - case IdMap.getId("empty"): - return Promise.resolve({}) - default: - return Promise.resolve(existing) - } - }, - }) - const swapService = new SwapService({ - manager: MockManager, - eventBusService, - swapRepository: swapRepo, - returnService, - }) - - it("fails if swap has no return request", async () => { - const res = swapService.receiveReturn(IdMap.getId("empty"), []) - await expect(res).rejects.toThrow("Swap has no return request") - }) - - it("sets requires action if return fails", async () => { - await swapService.receiveReturn(IdMap.getId("swap"), [ - { variant_id: IdMap.getId("1234"), quantity: 1 }, - ]) - - expect(swapRepo.save).toHaveBeenCalledWith({ - ...existing, - fulfillment_status: "requires_action", - }) - - expect(returnService.receiveReturn).toHaveBeenCalledTimes(1) - expect(returnService.receiveReturn).toHaveBeenCalledWith( - IdMap.getId("return-swap"), - [{ variant_id: IdMap.getId("1234"), quantity: 1 }], - undefined, - false - ) - }) - - it("fails to receive return when swap is canceled", async () => { - await expect( - swapService.receiveReturn(IdMap.getId("canceled")) - ).rejects.toThrow("Canceled swap cannot be registered as received") - }) - }) - }) - describe("createFulfillment", () => { beforeEach(() => { jest.clearAllMocks() @@ -757,6 +650,11 @@ describe("SwapService", () => { const cartService = { update: jest.fn(), + retrieve: jest + .fn() + .mockReturnValue( + Promise.resolve({ id: "cart", items: [{ id: "test-item" }] }) + ), withTransaction: function () { return this }, @@ -771,7 +669,6 @@ describe("SwapService", () => { eventBusService, swapRepository: swapRepo, lineItemService, - eventBusService, fulfillmentService, cartService, }) @@ -854,6 +751,12 @@ describe("SwapService", () => { } const cartService = { + retrieve: jest.fn().mockReturnValue( + Promise.resolve({ + id: "cart", + items: [{ id: "test-item", variant_id: "variant" }], + }) + ), update: () => { return Promise.resolve() }, @@ -885,18 +788,21 @@ describe("SwapService", () => { } describe("success", () => { - const existing = { - cart: { - items: [{ id: "1", variant_id: "variant", quantity: 2 }], - shipping_methods: [{ id: "method_1" }], - payment: { - good: "yes", - }, - shipping_address_id: 1234, + const cart = { + items: [{ id: "1", variant_id: "variant", quantity: 2 }], + shipping_methods: [{ id: "method_1" }], + payment: { + good: "yes", }, + shipping_address_id: 1234, + total: 1, + } + const existing = { other: "data", } + cartService.retrieve = () => cart + const swapRepo = MockRepository({ findOneWithRelations: () => Promise.resolve(existing), }) @@ -908,7 +814,6 @@ describe("SwapService", () => { totalsService, cartService, paymentProviderService, - eventBusService, shippingOptionService, inventoryService, }) @@ -931,7 +836,7 @@ describe("SwapService", () => { expect(swapRepo.save).toHaveBeenCalledWith({ ...existing, - difference_due: 100, + difference_due: 1, shipping_address_id: 1234, confirmed_at: expect.anything(), }) @@ -970,7 +875,6 @@ describe("SwapService", () => { totalsService, cartService, paymentProviderService, - eventBusService, shippingOptionService, inventoryService, }) diff --git a/packages/medusa/src/services/__tests__/system-tax.js b/packages/medusa/src/services/__tests__/system-tax.js new file mode 100644 index 0000000000..b032163790 --- /dev/null +++ b/packages/medusa/src/services/__tests__/system-tax.js @@ -0,0 +1,85 @@ +import SystemTaxService from "../system-tax" + +describe("SystemTaxService", () => { + describe("getTaxLines", () => { + const taxService = new SystemTaxService() + + const calculationContext = { + region: {}, + customer: {}, + allocation_map: {}, + shipping_address: {}, + } + + test("success", async () => { + const lines = await taxService.getTaxLines( + [ + { + item: { id: "line_id" }, + rates: [ + { rate: 20, name: "test", code: "test" }, + { rate: 5.5, name: "test_2", code: "test_2" }, + ], + }, + ], + [], + calculationContext + ) + expect(lines).toEqual([ + { + item_id: "line_id", + rate: 20, + name: "test", + code: "test", + }, + { + item_id: "line_id", + rate: 5.5, + name: "test_2", + code: "test_2", + }, + ]) + }) + + test("success w. shipping", async () => { + const lines = await taxService.getTaxLines( + [ + { + item: { id: "line_id" }, + rates: [ + { rate: 20, name: "test", code: "test" }, + { rate: 5.5, name: "test_2", code: "test_2" }, + ], + }, + ], + [ + { + shipping_method: { id: "sm_id" }, + rates: [{ rate: 20, name: "test", code: "test" }], + }, + ], + calculationContext + ) + expect(lines).toEqual([ + { + item_id: "line_id", + rate: 20, + name: "test", + code: "test", + }, + { + item_id: "line_id", + rate: 5.5, + name: "test_2", + code: "test_2", + }, + { + shipping_method_id: "sm_id", + rate: 20, + name: "test", + code: "test", + }, + ]) + }) + }) +}) diff --git a/packages/medusa/src/services/__tests__/tax-provider.js b/packages/medusa/src/services/__tests__/tax-provider.js new file mode 100644 index 0000000000..3b097528c7 --- /dev/null +++ b/packages/medusa/src/services/__tests__/tax-provider.js @@ -0,0 +1,281 @@ +import { MockManager, MockRepository } from "medusa-test-utils" +import TaxProviderService from "../tax-provider" + +describe("TaxProviderService", () => { + describe("retrieveProvider", () => { + const container = { + manager: MockManager, + taxRateService: {}, + systemTaxService: "system", + tp_test: "good", + } + + const providerService = new TaxProviderService(container) + + it("successfully retrieves system provider", () => { + const provider = providerService.retrieveProvider({ + tax_provider_id: null, + }) + expect(provider).toEqual("system") + }) + + it("successfully retrieves external provider", () => { + const provider = providerService.retrieveProvider({ + tax_provider_id: "test", + }) + expect(provider).toEqual("good") + }) + + it("fails when payment provider not found", () => { + expect.assertions(1) + + try { + providerService.retrieveProvider({ tax_provider_id: "unregistered" }) + } catch (err) { + expect(err.message).toEqual( + "Could not find a tax provider with id: unregistered" + ) + } + }) + }) + + describe("getTaxLines", () => { + const mockCalculateLineItemTaxes = jest.fn(() => [ + { + rate: 5, + name: "test vat", + code: "test_vat", + item_id: "item_1", + }, + ]) + const container = { + manager: MockManager, + lineItemTaxLineRepository: MockRepository({ create: (d) => d }), + systemTaxService: { + getTaxLines: mockCalculateLineItemTaxes, + }, + } + + test("success", async () => { + const providerService = new TaxProviderService(container) + providerService.getRegionRatesForProduct = jest.fn(() => []) + + const region = { id: "test", tax_provider_id: null } + const { cart, calculationContext: calcContext } = getTaxLineFactory({ + items: [{ id: "item_1", product_id: "prod_1" }], + region, + }) + + const expected = [ + { + item_id: "item_1", + rate: 5, + name: "test vat", + code: "test_vat", + metadata: undefined, + }, + ] + + const rates = await providerService.getTaxLines(cart.items, calcContext) + + expect(rates).toEqual(expected) + + expect(container.lineItemTaxLineRepository.create).toHaveBeenCalledTimes( + 1 + ) + expect(container.lineItemTaxLineRepository.create).toHaveBeenCalledWith( + expected[0] + ) + + expect(providerService.getRegionRatesForProduct).toHaveBeenCalledTimes(1) + expect(providerService.getRegionRatesForProduct).toHaveBeenCalledWith( + "prod_1", + region + ) + + expect(mockCalculateLineItemTaxes).toHaveBeenCalledTimes(1) + expect(mockCalculateLineItemTaxes).toHaveBeenCalledWith( + [ + { + item: cart.items[0], + rates: [], + }, + ], + [], + calcContext + ) + }) + }) + + describe("getRegionRatesForProduct", () => { + const container = { + manager: MockManager, + taxRateService: { + listByProduct: jest.fn(), + }, + } + + test("success", async () => { + container.taxRateService = { + listByProduct: jest.fn(() => Promise.resolve([])), + } + + const providerService = new TaxProviderService(container) + providerService.getCacheEntry = jest.fn(() => null) + providerService.setCache = jest.fn() + + const rates = await providerService.getRegionRatesForProduct("prod_id", { + id: "reg_id", + tax_rates: [], + tax_rate: 12.5, + }) + + const expected = [ + { + rate: 12.5, + name: "default", + code: "default", + }, + ] + expect(rates).toEqual(expected) + + expect(providerService.getCacheEntry).toHaveBeenCalledTimes(1) + expect(providerService.getCacheEntry).toHaveBeenCalledWith( + "prod_id", + "reg_id" + ) + + expect(providerService.setCache).toHaveBeenCalledTimes(1) + expect(providerService.setCache).toHaveBeenCalledWith( + "prod_id", + "reg_id", + expected + ) + }) + + test("success - without product rates", async () => { + container.taxRateService = { + listByProduct: jest.fn(() => Promise.resolve([])), + } + + const providerService = new TaxProviderService(container) + providerService.getCacheEntry = jest.fn(() => null) + providerService.setCache = jest.fn() + + const rates = await providerService.getRegionRatesForProduct("prod_id", { + id: "reg_id", + tax_rates: [{ id: "reg_rate", rate: 20, name: "PTR", code: "ptr" }], + tax_rate: 12.5, + }) + + const expected = [ + { + rate: 12.5, + name: "default", + code: "default", + }, + ] + expect(container.taxRateService.listByProduct).toHaveBeenCalledTimes(1) + expect(container.taxRateService.listByProduct).toHaveBeenCalledWith( + "prod_id", + { region_id: "reg_id" } + ) + + expect(providerService.setCache).toHaveBeenCalledTimes(1) + expect(providerService.setCache).toHaveBeenCalledWith( + "prod_id", + "reg_id", + expected + ) + + expect(rates).toEqual(expected) + }) + + test("success - with product rates", async () => { + container.taxRateService = { + listByProduct: jest.fn(() => + Promise.resolve([ + { + rate: 20, + name: "PTR", + code: "ptr", + }, + ]) + ), + } + + const providerService = new TaxProviderService(container) + providerService.getCacheEntry = jest.fn(() => null) + providerService.setCache = jest.fn() + + const rates = await providerService.getRegionRatesForProduct("prod_id", { + id: "reg_id", + tax_rates: [{ id: "reg_rate", rate: 20, name: "PTR", code: "ptr" }], + tax_rate: 12.5, + }) + + const expected = [ + { + rate: 20, + name: "PTR", + code: "ptr", + }, + ] + expect(container.taxRateService.listByProduct).toHaveBeenCalledTimes(1) + expect(container.taxRateService.listByProduct).toHaveBeenCalledWith( + "prod_id", + { region_id: "reg_id" } + ) + + expect(providerService.setCache).toHaveBeenCalledTimes(1) + expect(providerService.setCache).toHaveBeenCalledWith( + "prod_id", + "reg_id", + expected + ) + + expect(rates).toEqual(expected) + }) + }) + + describe("getCacheKey", () => { + const container = { + manager: MockManager, + productTaxRateService: {}, + systemTaxService: "system", + tp_test: "good", + } + + const providerService = new TaxProviderService(container) + + test("formats correctly", () => { + expect(providerService.getCacheKey("product", "region")).toEqual( + "txrtcache:product:region" + ) + }) + }) +}) + +const getTaxLineFactory = ({ items, region }) => { + const cart = { + shipping_methods: [], + items: items.map((i) => { + return { + id: i.id, + variant: { + product_id: i.product_id, + }, + } + }), + } + + const calculationContext = { + region, + customer: {}, + allocation_map: {}, + shipping_address: {}, + shipping_methods: [], + } + + return { cart, calculationContext } +} diff --git a/packages/medusa/src/services/__tests__/totals.js b/packages/medusa/src/services/__tests__/totals.js index 5127a8dec1..0b3426cd9c 100644 --- a/packages/medusa/src/services/__tests__/totals.js +++ b/packages/medusa/src/services/__tests__/totals.js @@ -60,9 +60,15 @@ const discounts = { } describe("TotalsService", () => { + const container = { + taxProviderService: {}, + taxCalculationStrategy: {}, + } + describe("getAllocationItemDiscounts", () => { let res - const totalsService = new TotalsService() + + const totalsService = new TotalsService(container) beforeEach(() => { jest.clearAllMocks() @@ -187,7 +193,7 @@ describe("TotalsService", () => { describe("getDiscountTotal", () => { let res - const totalsService = new TotalsService() + const totalsService = new TotalsService(container) const discountCart = { id: "discount_cart", @@ -275,7 +281,7 @@ describe("TotalsService", () => { describe("getRefundTotal", () => { let res - const totalsService = new TotalsService() + const totalsService = new TotalsService(container) const orderToRefund = { id: "refund-order", tax_rate: 25, @@ -441,7 +447,7 @@ describe("TotalsService", () => { }) describe("getShippingTotal", () => { let res - const totalsService = new TotalsService() + const totalsService = new TotalsService(container) beforeEach(() => { jest.clearAllMocks() @@ -469,10 +475,85 @@ describe("TotalsService", () => { }) describe("getTaxTotal", () => { let res - const totalsService = new TotalsService() + let totalsService + + const getTaxLinesMock = jest.fn(() => Promise.resolve([{ id: "line1" }])) + const calculateMock = jest.fn(() => Promise.resolve(20.3)) + const getAllocationMapMock = jest.fn(() => ({})) + + const cradle = { + taxProviderService: { + getTaxLines: getTaxLinesMock, + }, + taxCalculationStrategy: { + calculate: calculateMock, + }, + } beforeEach(() => { jest.clearAllMocks() + + totalsService = new TotalsService(cradle) + totalsService.getAllocationMap = getAllocationMapMock + }) + + it("uses order tax lines", async () => { + const order = { + object: "order", + tax_rate: null, + region: { + tax_rate: 25, + }, + customer: { + test: "test", + }, + shipping_address: { + test: "test", + }, + items: [ + { + unit_price: 20, + quantity: 2, + tax_lines: [{ id: "orderline1" }], + }, + ], + shipping_methods: [ + { + id: IdMap.getId("expensiveShipping"), + name: "Expensive Shipping", + price: 100, + provider_id: "default_provider", + profile_id: IdMap.getId("default"), + tax_lines: [], + data: { + extra: "hi", + }, + }, + ], + } + + res = await totalsService.getTaxTotal(order) + + expect(res).toEqual(20) + + expect(getAllocationMapMock).toHaveBeenCalledTimes(1) + expect(getAllocationMapMock).toHaveBeenCalledWith(order, {}) + + expect(getTaxLinesMock).toHaveBeenCalledTimes(0) + + expect(calculateMock).toHaveBeenCalledTimes(1) + expect(calculateMock).toHaveBeenCalledWith( + order.items, + [{ id: "orderline1" }], + { + shipping_address: order.shipping_address, + shipping_methods: order.shipping_methods, + is_return: false, + customer: order.customer, + region: order.region, + allocation_map: {}, + } + ) }) it("calculates tax", async () => { @@ -480,6 +561,12 @@ describe("TotalsService", () => { region: { tax_rate: 25, }, + customer: { + test: "test", + }, + shipping_address: { + test: "test", + }, items: [ { unit_price: 20, @@ -488,7 +575,7 @@ describe("TotalsService", () => { ], shipping_methods: [ { - _id: IdMap.getId("expensiveShipping"), + id: IdMap.getId("expensiveShipping"), name: "Expensive Shipping", price: 100, provider_id: "default_provider", @@ -500,15 +587,45 @@ describe("TotalsService", () => { ], } - res = totalsService.getTaxTotal(order) + res = await totalsService.getTaxTotal(order) - expect(res).toEqual(35) + expect(res).toEqual(20) + + expect(getAllocationMapMock).toHaveBeenCalledTimes(1) + expect(getAllocationMapMock).toHaveBeenCalledWith(order, {}) + + expect(getTaxLinesMock).toHaveBeenCalledTimes(1) + expect(getTaxLinesMock).toHaveBeenCalledWith( + [{ quantity: 2, unit_price: 20 }], + { + shipping_address: order.shipping_address, + shipping_methods: order.shipping_methods, + is_return: false, + customer: order.customer, + region: order.region, + allocation_map: {}, + } + ) + + expect(calculateMock).toHaveBeenCalledTimes(1) + expect(calculateMock).toHaveBeenCalledWith( + order.items, + [{ id: "line1" }], + { + shipping_address: order.shipping_address, + shipping_methods: order.shipping_methods, + is_return: false, + customer: order.customer, + region: order.region, + allocation_map: {}, + } + ) }) }) describe("getTotal", () => { let res - const totalsService = new TotalsService() + const totalsService = new TotalsService(container) beforeEach(() => { jest.clearAllMocks() @@ -538,7 +655,13 @@ describe("TotalsService", () => { }, ], } - res = totalsService.getTotal(order) + const getTaxTotalMock = jest.fn(() => Promise.resolve(35)) + totalsService.getTaxTotal = getTaxTotalMock + res = await totalsService.getTotal(order) + + expect(getTaxTotalMock).toHaveBeenCalledTimes(1) + expect(getTaxTotalMock).toHaveBeenCalledWith(order, undefined) + expect(res).toEqual(175) }) }) diff --git a/packages/medusa/src/services/cart.ts b/packages/medusa/src/services/cart.ts index 7b7fe1c67d..c8d993feea 100644 --- a/packages/medusa/src/services/cart.ts +++ b/packages/medusa/src/services/cart.ts @@ -32,6 +32,7 @@ import LineItemService from "./line-item" import PaymentProviderService from "./payment-provider" import ShippingOptionService from "./shipping-option" import CustomerService from "./customer" +import TaxProviderService from "./tax-provider" import DiscountService from "./discount" import GiftCardService from "./gift-card" import TotalsService from "./totals" @@ -45,6 +46,7 @@ type CartConstructorProps = { addressRepository: typeof AddressRepository paymentSessionRepository: typeof PaymentSessionRepository eventBusService: EventBusService + taxProviderService: TaxProviderService paymentProviderService: PaymentProviderService productService: ProductService productVariantService: ProductVariantService @@ -59,6 +61,10 @@ type CartConstructorProps = { customShippingOptionService: CustomShippingOptionService } +type TotalsConfig = { + force_taxes?: boolean +} + /* Provides layer to manipulate carts. * @implements BaseService */ @@ -82,6 +88,7 @@ class CartService extends BaseService { private shippingOptionService_: ShippingOptionService private discountService_: DiscountService private giftCardService_: GiftCardService + private taxProviderService_: TaxProviderService private totalsService_: TotalsService private addressRepository_: typeof AddressRepository private paymentSessionRepository_: typeof PaymentSessionRepository @@ -96,6 +103,7 @@ class CartService extends BaseService { paymentProviderService, productService, productVariantService, + taxProviderService, regionService, lineItemService, shippingOptionService, @@ -110,59 +118,25 @@ class CartService extends BaseService { }: CartConstructorProps) { super() - /** @private @const {EntityManager} */ this.manager_ = manager - - /** @private @const {ShippingMethodRepository} */ this.shippingMethodRepository_ = shippingMethodRepository - - /** @private @const {CartRepository} */ this.cartRepository_ = cartRepository - - /** @private @const {EventBus} */ this.eventBus_ = eventBusService - - /** @private @const {ProductVariantService} */ this.productVariantService_ = productVariantService - - /** @private @const {ProductService} */ this.productService_ = productService - - /** @private @const {RegionService} */ this.regionService_ = regionService - - /** @private @const {LineItemService} */ this.lineItemService_ = lineItemService - - /** @private @const {PaymentProviderService} */ this.paymentProviderService_ = paymentProviderService - - /** @private @const {CustomerService} */ this.customerService_ = customerService - - /** @private @const {ShippingOptionService} */ this.shippingOptionService_ = shippingOptionService - - /** @private @const {DiscountService} */ this.discountService_ = discountService - - /** @private @const {GiftCardService} */ this.giftCardService_ = giftCardService - - /** @private @const {TotalsService} */ this.totalsService_ = totalsService - - /** @private @const {AddressRepository} */ this.addressRepository_ = addressRepository - - /** @private @const {PaymentSessionRepository} */ this.paymentSessionRepository_ = paymentSessionRepository - - /** @private @const {InventoryService} */ this.inventoryService_ = inventoryService - - /** @private @const {CustomShippingOptionService} */ this.customShippingOptionService_ = customShippingOptionService + this.taxProviderService_ = taxProviderService } withTransaction(transactionManager: EntityManager): CartService { @@ -172,6 +146,7 @@ class CartService extends BaseService { const cloned = new CartService({ manager: transactionManager, + taxProviderService: this.taxProviderService_, cartRepository: this.cartRepository_, eventBusService: this.eventBus_, paymentProviderService: this.paymentProviderService_, @@ -196,25 +171,6 @@ class CartService extends BaseService { return cloned } - /** - * Used to validate cart ids. Throws an error if the cast fails - * @param {string} rawId - the raw cart id to validate. - * @return {string} the validated id - */ - /** - * Contents of a line item - * @typedef {(object | array)} LineItemContent - * @property {number} unit_price - the price of the content - * @property {object} variant - the product variant of the content - * @property {object} product - the product of the content - * @property {number} quantity - the quantity of the content - */ - - /** - * A collection of contents grouped in the same line item - * @typedef {LineItemContent[]} LineItemContentArray - */ - transformQueryForTotals_( config: FindConfig ): FindConfig & { totalsToSelect: TotalField[] } { @@ -243,6 +199,7 @@ class CartService extends BaseService { if (totalsToSelect.length > 0) { const relationSet = new Set(relations) relationSet.add("items") + relationSet.add("items.tax_lines") relationSet.add("gift_cards") relationSet.add("discounts") relationSet.add("discounts.rule") @@ -252,6 +209,7 @@ class CartService extends BaseService { // relationSet.add("discounts.parent_discount.regions") relationSet.add("shipping_methods") relationSet.add("region") + relationSet.add("region.tax_rates") relations = Array.from(relationSet.values()) select = select.filter((v) => !totalFields.includes(v)) @@ -266,14 +224,17 @@ class CartService extends BaseService { async decorateTotals_( cart: Cart, - totalsToSelect: TotalField[] + totalsToSelect: TotalField[], + options: TotalsConfig = { force_taxes: false } ): Promise { - const totals: { [K in TotalField]?: number } = {} + const totals: { [K in TotalField]?: number | null } = {} for (const key of totalsToSelect) { switch (key) { case "total": { - totals.total = await this.totalsService_.getTotal(cart) + totals.total = await this.totalsService_.getTotal(cart, { + force_taxes: options.force_taxes, + }) break } case "shipping_total": { @@ -284,7 +245,10 @@ class CartService extends BaseService { totals.discount_total = this.totalsService_.getDiscountTotal(cart) break case "tax_total": - totals.tax_total = await this.totalsService_.getTaxTotal(cart) + totals.tax_total = await this.totalsService_.getTaxTotal( + cart, + options.force_taxes + ) break case "gift_card_total": totals.gift_card_total = this.totalsService_.getGiftCardTotal(cart) @@ -301,9 +265,9 @@ class CartService extends BaseService { } /** - * @param {Object} selector - the query object for find - * @param {Object} config - config object - * @return {Promise} the result of the find operation + * @param selector - the query object for find + * @param config - config object + * @return the result of the find operation */ async list( selector: FilterableCartProps, @@ -317,13 +281,15 @@ class CartService extends BaseService { /** * Gets a cart by id. - * @param {string} cartId - the id of the cart to get. - * @param {Object} options - the options to get a cart - * @return {Promise} the cart document. + * @param cartId - the id of the cart to get. + * @param options - the options to get a cart + * @param totalsConfig - configuration for retrieval of totals + * @return the cart document. */ async retrieve( cartId: string, - options: FindConfig = {} + options: FindConfig = {}, + totalsConfig: TotalsConfig = {} ): Promise { const cartRepo = this.manager_.getCustomRepository(this.cartRepository_) const validatedId = this.validateId_(cartId) @@ -358,13 +324,13 @@ class CartService extends BaseService { ) } - return await this.decorateTotals_(raw, totalsToSelect) + return await this.decorateTotals_(raw, totalsToSelect, totalsConfig) } /** * Creates a cart. - * @param {Object} data - the data to create the cart with - * @return {Promise} the result of the create operation + * @param data - the data to create the cart with + * @return the result of the create operation */ async create(data: CartCreateProps): Promise { return this.atomicPhase_(async (manager: EntityManager) => { @@ -435,7 +401,7 @@ class CartService extends BaseService { ] for (const k of remainingFields) { - if (typeof data[k] !== "undefined") { + if (typeof data[k] !== "undefined" && k !== "object") { toCreate[k] = data[k] } } @@ -453,9 +419,9 @@ class CartService extends BaseService { /** * Removes a line item from the cart. - * @param {string} cartId - the id of the cart that we will remove from - * @param {LineItem} lineItemId - the line item to remove. - * @return {Promise} the result of the update operation + * @param cartId - the id of the cart that we will remove from + * @param lineItemId - the line item to remove. + * @return the result of the update operation */ async removeLineItem(cartId: string, lineItemId: string): Promise { return this.atomicPhase_(async (manager: EntityManager) => { @@ -505,9 +471,9 @@ class CartService extends BaseService { * Checks if a given line item has a shipping method that can fulfill it. * Returns true if all products in the cart can be fulfilled with the current * shipping methods. - * @param {ShippingMethod[]} shippingMethods - the set of shipping methods to check from - * @param {LineItem} lineItem - the line item - * @return {boolean} + * @param shippingMethods - the set of shipping methods to check from + * @param lineItem - the line item + * @return boolean representing wheter shipping method is validated */ validateLineItemShipping_( shippingMethods: ShippingMethod[], @@ -535,9 +501,9 @@ class CartService extends BaseService { /** * Adds a line item to the cart. - * @param {string} cartId - the id of the cart that we will add to - * @param {LineItem} lineItem - the line item to add. - * @return {Promise} the result of the update operation + * @param cartId - the id of the cart that we will add to + * @param lineItem - the line item to add. + * @return the result of the update operation */ async addLineItem(cartId: string, lineItem: LineItem): Promise { return this.atomicPhase_(async (manager: EntityManager) => { @@ -613,11 +579,10 @@ class CartService extends BaseService { /** * Updates a cart's existing line item. - * @param {string} cartId - the id of the cart to update - * @param {string} lineItemId - the id of the line item to update. - * @param {LineItemUpdate} lineItemUpdate - the line item to update. Must - * include an id field. - * @return {Promise} the result of the update operation + * @param cartId - the id of the cart to update + * @param lineItemId - the id of the line item to update. + * @param lineItemUpdate - the line item to update. Must include an id field. + * @return the result of the update operation */ async updateLineItem( cartId: string, @@ -669,8 +634,9 @@ class CartService extends BaseService { * shipping discount * If a free shipping is present, we set shipping methods price to 0 * if a free shipping was present, we set shipping methods to original amount - * @param {Cart} cart - the the cart to adjust free shipping for - * @param {boolean} shouldAdd - flag to indicate, if we should add or remove + * @param cart - the the cart to adjust free shipping for + * @param shouldAdd - flag to indicate, if we should add or remove + * @return void */ async adjustFreeShipping_(cart: Cart, shouldAdd: boolean): Promise { if (cart.shipping_methods?.length) { @@ -851,9 +817,9 @@ class CartService extends BaseService { /** * Sets the customer id of a cart - * @param {Cart} cart - the cart to add email to - * @param {string} customerId - the customer to add to cart - * @return {Promise} the result of the update operation + * @param cart - the cart to add email to + * @param customerId - the customer to add to cart + * @return the result of the update operation */ async updateCustomerId_(cart: Cart, customerId: string): Promise { const customer = await this.customerService_ @@ -867,8 +833,8 @@ class CartService extends BaseService { /** * Creates or fetches a user based on an email. - * @param {string} email - the email to use - * @return {Promise} the resultign customer object + * @param email - the email to use + * @return the resultign customer object */ async createOrFetchUserFromEmail_(email: string): Promise { const schema = Validator.string().email().required() @@ -896,12 +862,10 @@ class CartService extends BaseService { /** * Updates the cart's billing address. - * @param {Cart} cart - the cart to update - * @param {Address | string} addressOrId - the value to set the billing - * address to - * @param {AddressRepository} addrRepo - the repository to use for address - * updates - * @return {Promise} the result of the update operation + * @param cart - the cart to update + * @param addressOrId - the value to set the billing address to + * @param addrRepo - the repository to use for address updates + * @return the result of the update operation */ async updateBillingAddress_( cart: Cart, @@ -941,12 +905,10 @@ class CartService extends BaseService { /** * Updates the cart's shipping address. - * @param {Cart} cart - the cart to update - * @param {Address | string} addressOrId - the value to set the shipping - * address to - * @param {AddressRepository} addrRepo - the repository to use for address - * updates - * @return {Promise} the result of the update operation + * @param cart - the cart to update + * @param addressOrId - the value to set the shipping address to + * @param addrRepo - the repository to use for address updates + * @return the result of the update operation */ async updateShippingAddress_( cart: Cart, @@ -1030,9 +992,9 @@ class CartService extends BaseService { * If discount besides free shipping is already applied, this * will be overwritten * Throws if discount regions does not include the cart region - * @param {Cart} cart - the cart to update - * @param {string} discountCode - the discount code - * @return {Promise} the result of the update operation + * @param cart - the cart to update + * @param discountCode - the discount code + * @return the result of the update operation */ async applyDiscount(cart: Cart, discountCode: string): Promise { const discount = await this.discountService_.retrieveByCode(discountCode, [ @@ -1129,9 +1091,9 @@ class CartService extends BaseService { /** * Removes a discount based on a discount code. - * @param {string} cartId - the id of the cart to remove from - * @param {string} discountCode - the discount code to remove - * @return {Promise} the resulting cart + * @param cartId - the id of the cart to remove from + * @param discountCode - the discount code to remove + * @return the resulting cart */ async removeDiscount(cartId: string, discountCode: string): Promise { return this.atomicPhase_(async (manager: EntityManager) => { @@ -1167,19 +1129,11 @@ class CartService extends BaseService { }) } - /** - * A payment method represents a way for the customer to pay. The payment - * method will typically come from one of the payment sessions. - * @typedef {object} PaymentMethod - * @property {string} provider_id - the identifier of the payment method's - * provider - * @property {object} data - the data associated with the payment method - */ - /** * Updates the currently selected payment session. - * @param {string} cartId - the id of the cart to update the payment session for - * @param {object} update - the data to update the payment session with + * @param cartId - the id of the cart to update the payment session for + * @param update - the data to update the payment session with + * @return the resulting cart */ async updatePaymentSession(cartId: string, update: object): Promise { return this.atomicPhase_(async (manager: EntityManager) => { @@ -1209,11 +1163,11 @@ class CartService extends BaseService { * a payment object, that we will use to update our cart payment with. * Additionally, if the payment does not require more or fails, we will * set the payment on the cart. - * @param {string} cartId - the id of the cart to authorize payment for - * @param {object} context - object containing whatever is relevant for + * @param cartId - the id of the cart to authorize payment for + * @param context - object containing whatever is relevant for * authorizing the payment with the payment provider. As an example, * this could be IP address or similar for fraud handling. - * @return {Promise} the resulting cart + * @return the resulting cart */ async authorizePayment(cartId: string, context: Record = {}): Promise { return this.atomicPhase_(async (manager: EntityManager) => { @@ -1265,9 +1219,9 @@ class CartService extends BaseService { /** * Sets a payment method for a cart. - * @param {string} cartId - the id of the cart to add payment method to - * @param {string} providerId - the id of the provider to be set to the cart - * @return {Promise} result of update operation + * @param cartId - the id of the cart to add payment method to + * @param providerId - the id of the provider to be set to the cart + * @return result of update operation */ async setPaymentSession(cartId: string, providerId: string): Promise { return this.atomicPhase_(async (manager: EntityManager) => { @@ -1334,9 +1288,8 @@ class CartService extends BaseService { * provider. Additional calls will ensure that payment sessions have correct * amounts, currencies, etc. as well as make sure to filter payment sessions * that are not available for the cart's region. - * @param {Cart | string} cartOrCartId - the id of the cart to set payment - * session for - * @return {Promise} the result of the update operation. + * @param cartOrCartId - the id of the cart to set payment session for + * @return the result of the update operation. */ async setPaymentSessions(cartOrCartId: Cart | string): Promise { return this.atomicPhase_(async (manager: EntityManager) => { @@ -1345,36 +1298,42 @@ class CartService extends BaseService { const cartId = typeof cartOrCartId === `string` ? cartOrCartId : cartOrCartId.id - const cart = await this.retrieve(cartId, { - select: [ - "gift_card_total", - "subtotal", - "tax_total", - "shipping_total", - "discount_total", - "total", - ], - relations: [ - "items", - "discounts", - "discounts.rule", - "discounts.rule.valid_for", - "gift_cards", - "billing_address", - "shipping_address", - "region", - "region.payment_providers", - "payment_sessions", - "customer", - ], - }) + const cart = await this.retrieve( + cartId, + { + select: [ + "total", + "subtotal", + "tax_total", + "discount_total", + "shipping_total", + "gift_card_total", + ], + relations: [ + "items", + "discounts", + "discounts.rule", + "discounts.rule.valid_for", + "gift_cards", + "shipping_methods", + "billing_address", + "shipping_address", + "region", + "region.tax_rates", + "region.payment_providers", + "payment_sessions", + "customer", + ], + }, + { force_taxes: true } + ) - const region = cart.region + const { total, region } = cart - if (typeof cart.total === "undefined") { + if (typeof total === "undefined") { throw new MedusaError( MedusaError.Types.UNEXPECTED_STATE, - "cart.total should be defined" + "cart.total must be defined" ) } @@ -1383,7 +1342,7 @@ class CartService extends BaseService { if (cart.payment_sessions && cart.payment_sessions.length) { for (const session of cart.payment_sessions) { if ( - cart.total <= 0 || + total <= 0 || !region.payment_providers.find( ({ id }) => id === session.provider_id ) @@ -1400,7 +1359,7 @@ class CartService extends BaseService { } } - if (cart.total > 0) { + if (total > 0) { // If only one payment session exists, we preselect it if (region.payment_providers.length === 1 && !cart.payment_session) { const p = region.payment_providers[0] @@ -1426,10 +1385,10 @@ class CartService extends BaseService { /** * Removes a payment session from the cart. - * @param {string} cartId - the id of the cart to remove from - * @param {string} providerId - the id of the provider whoose payment session + * @param cartId - the id of the cart to remove from + * @param providerId - the id of the provider whoose payment session * should be removed. - * @return {Promise} the resulting cart. + * @return the resulting cart. */ async deletePaymentSession( cartId: string, @@ -1470,8 +1429,8 @@ class CartService extends BaseService { /** * Refreshes a payment session on a cart - * @param {string} cartId - the id of the cart to remove from - * @param {string} providerId - the id of the provider whoose payment session + * @param cartId - the id of the cart to remove from + * @param providerId - the id of the provider whoose payment session * should be removed. * @return {Promise} the resulting cart. */ @@ -1512,10 +1471,10 @@ class CartService extends BaseService { * Shipping Option is a possible way to ship an order. Shipping Methods may * also have additional details in the data field such as an id for a package * shop. - * @param {string} cartId - the id of the cart to add shipping method to - * @param {string} optionId - id of shipping option to add as valid method - * @param {Object} data - the fulmillment data for the method - * @return {Promise} the result of the update operation + * @param cartId - the id of the cart to add shipping method to + * @param optionId - id of shipping option to add as valid method + * @param data - the fulmillment data for the method + * @return the result of the update operation */ async addShippingMethod( cartId: string, @@ -1610,9 +1569,9 @@ class CartService extends BaseService { /** * Finds the cart's custom shipping options based on the passed option id. * throws if custom options is not empty and no shipping option corresponds to optionId - * @param {Object} cartCustomShippingOptions - the cart's custom shipping options - * @param {string} optionId - id of the normal or custom shipping option to find in the cartCustomShippingOptions - * @return {CustomShippingOption | undefined} + * @param cartCustomShippingOptions - the cart's custom shipping options + * @param optionId - id of the normal or custom shipping option to find in the cartCustomShippingOptions + * @return custom shipping option */ findCustomShippingOption( cartCustomShippingOptions: CustomShippingOption[], @@ -1635,10 +1594,10 @@ class CartService extends BaseService { /** * Set's the region of a cart. - * @param {Cart} cart - the cart to set region on - * @param {string} regionId - the id of the region to set the region to - * @param {string} countryCode - the country code to set the country to - * @return {Promise} the result of the update operation + * @param cart - the cart to set region on + * @param regionId - the id of the region to set the region to + * @param countryCode - the country code to set the country to + * @return the result of the update operation */ async setRegion_( cart: Cart, @@ -1793,9 +1752,8 @@ class CartService extends BaseService { /** * Deletes a cart from the database. Completed carts cannot be deleted. - * @param {string} cartId - the id of the cart to delete - * @return {Promise} the deleted cart or undefined if the cart was - * not found. + * @param cartId - the id of the cart to delete + * @return the deleted cart or undefined if the cart was not found. */ async delete(cartId: string): Promise { return await this.atomicPhase_(async (manager: EntityManager) => { @@ -1832,10 +1790,10 @@ class CartService extends BaseService { * Dedicated method to set metadata for a cart. * To ensure that plugins does not overwrite each * others metadata fields, setMetadata is provided. - * @param {string} cartId - the cart to apply metadata to. - * @param {string} key - key for metadata field - * @param {string} value - value for metadata field. - * @return {Promise} resolves to the updated result. + * @param cartId - the cart to apply metadata to. + * @param key - key for metadata field + * @param value - value for metadata field. + * @return resolves to the updated result. */ async setMetadata( cartId: string, @@ -1869,11 +1827,35 @@ class CartService extends BaseService { }) } + async createTaxLines(id: string): Promise { + return this.atomicPhase_(async (manager: EntityManager) => { + const cart = await this.retrieve(id, { + relations: [ + "items", + "gift_cards", + "discounts", + "discounts.rule", + "discounts.rule.valid_for", + "shipping_methods", + "region", + "region.tax_rates", + ], + }) + const calculationContext = this.totalsService_.getCalculationContext(cart) + + await this.taxProviderService_ + .withTransaction(manager) + .createTaxLines(cart, calculationContext) + + return cart + }) + } + /** * Dedicated method to delete metadata for a cart. - * @param {string} cartId - the cart to delete metadata from. - * @param {string} key - key for metadata field - * @return {Promise} resolves to the updated result. + * @param cartId - the cart to delete metadata from. + * @param key - key for metadata field + * @return resolves to the updated result. */ async deleteMetadata(cartId: string, key: string): Promise { return this.atomicPhase_(async (manager: EntityManager) => { diff --git a/packages/medusa/src/services/claim.js b/packages/medusa/src/services/claim.js index a2b42aaa3c..d8c7d5ff80 100644 --- a/packages/medusa/src/services/claim.js +++ b/packages/medusa/src/services/claim.js @@ -13,63 +13,40 @@ class ClaimService extends BaseService { constructor({ manager, - claimRepository, addressRepository, + claimItemService, + claimRepository, + eventBusService, fulfillmentProviderService, fulfillmentService, + inventoryService, lineItemService, - totalsService, paymentProviderService, + regionService, returnService, shippingOptionService, - claimItemService, - regionService, - inventoryService, - eventBusService, + taxProviderService, + totalsService, }) { super() /** @private @constant {EntityManager} */ this.manager_ = manager - /** @private @constant {ClaimRepository} */ - this.claimRepository_ = claimRepository - - /** @private @constant {AddressRepository} */ this.addressRepo_ = addressRepository - - /** @private @constant {FulfillmentProviderService} */ - this.fulfillmentProviderService_ = fulfillmentProviderService - - /** @private @constant {PaymentProviderService} */ - this.paymentProviderService_ = paymentProviderService - - /** @private @constant {LineItemService} */ - this.lineItemService_ = lineItemService - - /** @private @constant {RegionService} */ - this.regionService_ = regionService - - /** @private @constant {ReturnService} */ - this.returnService_ = returnService - - /** @private @constant {FulfillmentService} */ - this.fulfillmentService_ = fulfillmentService - - /** @private @constant {ClaimItemService} */ this.claimItemService_ = claimItemService - - /** @private @constant {TotalsService} */ - this.totalsService_ = totalsService - - /** @private @constant {InventoryService} */ - this.inventoryService_ = inventoryService - - /** @private @constant {EventBus} */ + this.claimRepository_ = claimRepository this.eventBus_ = eventBusService - - /** @private @constant {ShippingOptionService} */ + this.fulfillmentProviderService_ = fulfillmentProviderService + this.fulfillmentService_ = fulfillmentService + this.inventoryService_ = inventoryService + this.lineItemService_ = lineItemService + this.paymentProviderService_ = paymentProviderService + this.regionService_ = regionService + this.returnService_ = returnService this.shippingOptionService_ = shippingOptionService + this.taxProviderService_ = taxProviderService + this.totalsService_ = totalsService } withTransaction(manager) { @@ -79,19 +56,20 @@ class ClaimService extends BaseService { const cloned = new ClaimService({ manager, - claimRepository: this.claimRepository_, addressRepository: this.addressRepo_, + claimItemService: this.claimItemService_, + claimRepository: this.claimRepository_, + eventBusService: this.eventBus_, fulfillmentProviderService: this.fulfillmentProviderService_, fulfillmentService: this.fulfillmentService_, - paymentProviderService: this.paymentProviderService_, + inventoryService: this.inventoryService_, lineItemService: this.lineItemService_, + paymentProviderService: this.paymentProviderService_, regionService: this.regionService_, returnService: this.returnService_, - claimItemService: this.claimItemService_, - eventBusService: this.eventBus_, - totalsService: this.totalsService_, - inventoryService: this.inventoryService_, shippingOptionService: this.shippingOptionService_, + totalsService: this.totalsService_, + taxProviderService: this.taxProviderService_, }) cloned.transactionManager_ = manager @@ -198,7 +176,7 @@ class ClaimService extends BaseService { for (const item of claim_items) { const line = await this.lineItemService_.retrieve(item.item_id, { - relations: ["order", "swap", "claim_order"], + relations: ["order", "swap", "claim_order", "tax_lines"], }) if ( @@ -261,25 +239,29 @@ class ClaimService extends BaseService { toRefund = await this.totalsService_.getRefundTotal(order, lines) } - for (const item of additional_items) { - await this.inventoryService_ - .withTransaction(manager) - .confirmInventory(item.variant_id, item.quantity) - } - - const newItems = await Promise.all( - additional_items.map((i) => - this.lineItemService_ + let newItems = [] + if (typeof additional_items !== "undefined") { + for (const item of additional_items) { + await this.inventoryService_ .withTransaction(manager) - .generate(i.variant_id, order.region_id, i.quantity) - ) - ) + .confirmInventory(item.variant_id, item.quantity) + } - for (const newItem of newItems) { - await this.inventoryService_ - .withTransaction(manager) - .adjustInventory(newItem.variant_id, -newItem.quantity) + newItems = await Promise.all( + additional_items.map((i) => + this.lineItemService_ + .withTransaction(manager) + .generate(i.variant_id, order.region_id, i.quantity) + ) + ) + + for (const newItem of newItems) { + await this.inventoryService_ + .withTransaction(manager) + .adjustInventory(newItem.variant_id, -newItem.quantity) + } } + const evaluatedNoNotification = no_notification !== undefined ? no_notification : order.no_notification @@ -296,6 +278,18 @@ class ClaimService extends BaseService { const result = await claimRepo.save(created) + if (result.additional_items && result.additional_items.length) { + const calcContext = this.totalsService_.getCalculationContext(order) + const lineItems = await this.lineItemService_ + .withTransaction(manager) + .list({ + id: result.additional_items.map((i) => i.id), + }) + await this.taxProviderService_ + .withTransaction(manager) + .createTaxLines(lineItems, calcContext) + } + if (shipping_methods) { for (const method of shipping_methods) { if (method.id) { @@ -366,7 +360,9 @@ class ClaimService extends BaseService { const claim = await this.retrieve(id, { relations: [ "additional_items", + "additional_items.tax_lines", "shipping_methods", + "shipping_methods.tax_lines", "shipping_address", "order", "order.billing_address", diff --git a/packages/medusa/src/services/fulfillment.js b/packages/medusa/src/services/fulfillment.js index b2cd6b71bc..a3b6ab1451 100644 --- a/packages/medusa/src/services/fulfillment.js +++ b/packages/medusa/src/services/fulfillment.js @@ -299,7 +299,7 @@ class FulfillmentService extends BaseService { const now = new Date() fulfillment.shipped_at = now - fulfillment.tracking_links = trackingLinks.map((tl) => + fulfillment.tracking_links = (trackingLinks || []).map((tl) => trackingLinkRepo.create(tl) ) diff --git a/packages/medusa/src/services/index.ts b/packages/medusa/src/services/index.ts index 9e3ff422f1..1567701c18 100644 --- a/packages/medusa/src/services/index.ts +++ b/packages/medusa/src/services/index.ts @@ -36,3 +36,6 @@ export { default as SystemPaymentProviderService } from "./system-payment-provid export { default as TotalsService } from "./totals" export { default as TransactionService } from "./transaction" export { default as UserService } from "./user" +export { default as TaxRateService } from "./tax-rate" +export { default as TaxProviderService } from "./tax-provider" +export { default as ProductTypeService } from "./product-type" diff --git a/packages/medusa/src/services/line-item.js b/packages/medusa/src/services/line-item.js index d02c582c07..9f484cac18 100644 --- a/packages/medusa/src/services/line-item.js +++ b/packages/medusa/src/services/line-item.js @@ -9,6 +9,7 @@ class LineItemService extends BaseService { constructor({ manager, lineItemRepository, + lineItemTaxLineRepository, productVariantService, productService, regionService, @@ -22,6 +23,9 @@ class LineItemService extends BaseService { /** @private @const {LineItemRepository} */ this.lineItemRepository_ = lineItemRepository + /** @private @const {typeof LineItemTaxLineRepository} */ + this.itemTaxLineRepo_ = lineItemTaxLineRepository + /** @private @const {ProductVariantService} */ this.productVariantService_ = productVariantService @@ -43,6 +47,7 @@ class LineItemService extends BaseService { const cloned = new LineItemService({ manager: transactionManager, lineItemRepository: this.lineItemRepository_, + lineItemTaxLineRepository: this.itemTaxLineRepo_, productVariantService: this.productVariantService_, productService: this.productService_, regionService: this.regionService_, @@ -89,6 +94,49 @@ class LineItemService extends BaseService { return lineItem } + /** + * Creates return line items for a given cart based on the return items in a + * return. + * @param {string} returnId - the id to generate return items from. + * @param {string} cartId - the cart to assign the return line items to. + * @return {Promise} the created line items + */ + async createReturnLines(returnId, cartId) { + const lineItemRepo = this.manager_.getCustomRepository( + this.lineItemRepository_ + ) + + const itemTaxLineRepo = this.manager_.getCustomRepository( + this.itemTaxLineRepo_ + ) + + const items = await lineItemRepo.findByReturn(returnId) + + const toCreate = items.map((i) => + lineItemRepo.create({ + cart_id: cartId, + thumbnail: i.thumbnail, + is_return: true, + title: i.title, + variant_id: i.variant_id, + unit_price: -1 * i.unit_price, + quantity: i.return_item.quantity, + allow_discounts: i.allow_discounts, + tax_lines: i.tax_lines.map((tl) => { + return itemTaxLineRepo.create({ + name: tl.name, + code: tl.code, + rate: tl.rate, + metadata: tl.metadata, + }) + }), + metadata: i.metadata, + }) + ) + + return await lineItemRepo.save(toCreate) + } + async generate(variantId, regionId, quantity, config = {}) { return this.atomicPhase_(async (manager) => { const variant = await this.productVariantService_ diff --git a/packages/medusa/src/services/order.js b/packages/medusa/src/services/order.js index b2fd285710..db9f2d78c4 100644 --- a/packages/medusa/src/services/order.js +++ b/packages/medusa/src/services/order.js @@ -201,7 +201,9 @@ class OrderService extends BaseService { const raw = await orderRepo.find(query) - return raw.map((r) => this.decorateTotals_(r, totalsToSelect)) + return await Promise.all( + raw.map(async (r) => await this.decorateTotals_(r, totalsToSelect)) + ) } async listAndCount( @@ -258,7 +260,9 @@ class OrderService extends BaseService { const raw = await orderRepo.findWithRelations(rels, query) const count = await orderRepo.count(query) - const orders = raw.map((r) => this.decorateTotals_(r, totalsToSelect)) + const orders = await Promise.all( + raw.map(async (r) => await this.decorateTotals_(r, totalsToSelect)) + ) return [orders, count] } @@ -293,10 +297,13 @@ class OrderService extends BaseService { if (totalsToSelect.length > 0) { const relationSet = new Set(relations) relationSet.add("items") + relationSet.add("items.tax_lines") relationSet.add("swaps") relationSet.add("swaps.additional_items") + relationSet.add("swaps.additional_items.tax_lines") relationSet.add("claims") relationSet.add("claims.additional_items") + relationSet.add("claims.additional_items.tax_lines") relationSet.add("discounts") relationSet.add("discounts.rule") relationSet.add("discounts.rule.valid_for") @@ -304,15 +311,21 @@ class OrderService extends BaseService { relationSet.add("gift_card_transactions") relationSet.add("refunds") relationSet.add("shipping_methods") + relationSet.add("shipping_methods.tax_lines") relationSet.add("region") relations = [...relationSet] select = select.filter((v) => !totalFields.includes(v)) } + const toSelect = [...select] + if (toSelect.length > 0 && toSelect.indexOf("tax_rate") === -1) { + toSelect.push("tax_rate") + } + return { relations, - select, + select: toSelect, totalsToSelect, } } @@ -352,8 +365,7 @@ class OrderService extends BaseService { ) } - const order = this.decorateTotals_(raw, totalsToSelect) - return order + return await this.decorateTotals_(raw, totalsToSelect) } /** @@ -389,7 +401,7 @@ class OrderService extends BaseService { ) } - const order = this.decorateTotals_(raw, totalsToSelect) + const order = await this.decorateTotals_(raw, totalsToSelect) return order } @@ -427,7 +439,7 @@ class OrderService extends BaseService { ) } - const order = this.decorateTotals_(raw, totalsToSelect) + const order = await this.decorateTotals_(raw, totalsToSelect) return order } @@ -574,7 +586,6 @@ class OrderService extends BaseService { email: cart.email, customer_id: cart.customer_id, cart_id: cart.id, - tax_rate: region.tax_rate, currency_code: region.currency_code, metadata: cart.metadata || {}, } @@ -1022,6 +1033,7 @@ class OrderService extends BaseService { order.status = "canceled" order.fulfillment_status = "canceled" order.payment_status = "canceled" + order.canceled_at = new Date() const orderRepo = manager.getCustomRepository(this.orderRepository_) const result = await orderRepo.save(order) @@ -1398,79 +1410,86 @@ class OrderService extends BaseService { }) } - decorateTotals_(order, totalsFields = []) { - if (totalsFields.includes("shipping_total")) { - order.shipping_total = this.totalsService_.getShippingTotal(order) - } - if (totalsFields.includes("gift_card_total")) { - order.gift_card_total = this.totalsService_.getGiftCardTotal(order) - } - if (totalsFields.includes("discount_total")) { - order.discount_total = this.totalsService_.getDiscountTotal(order) - } - if (totalsFields.includes("tax_total")) { - order.tax_total = this.totalsService_.getTaxTotal(order) - } - if (totalsFields.includes("subtotal")) { - order.subtotal = this.totalsService_.getSubtotal(order) - } - if (totalsFields.includes("total")) { - order.total = this.totalsService_.getTotal(order) - } - if (totalsFields.includes("refunded_total")) { - order.refunded_total = this.totalsService_.getRefundedTotal(order) - } - if (totalsFields.includes("paid_total")) { - order.paid_total = this.totalsService_.getPaidTotal(order) - } - if (totalsFields.includes("refundable_amount")) { - const paid_total = this.totalsService_.getPaidTotal(order) - const refunded_total = this.totalsService_.getRefundedTotal(order) - order.refundable_amount = paid_total - refunded_total - } - - if (totalsFields.includes("items.refundable")) { - order.items = order.items.map((i) => ({ - ...i, - refundable: this.totalsService_.getLineItemRefund(order, { - ...i, - quantity: i.quantity - (i.returned_quantity || 0), - }), - })) - } - - if ( - totalsFields.includes("swaps.additional_items.refundable") && - order.swaps && - order.swaps.length - ) { - for (const s of order.swaps) { - s.additional_items = s.additional_items.map((i) => ({ - ...i, - refundable: this.totalsService_.getLineItemRefund(order, { + async decorateTotals_(order, totalsFields = []) { + for (const totalField of totalsFields) { + switch (totalField) { + case "shipping_total": { + order.shipping_total = this.totalsService_.getShippingTotal(order) + break + } + case "gift_card_total": { + order.gift_card_total = this.totalsService_.getGiftCardTotal(order) + break + } + case "discount_total": { + order.discount_total = this.totalsService_.getDiscountTotal(order) + break + } + case "tax_total": { + order.tax_total = await this.totalsService_.getTaxTotal(order) + break + } + case "subtotal": { + order.subtotal = this.totalsService_.getSubtotal(order) + break + } + case "total": { + order.total = await this.totalsService_.getTotal(order) + break + } + case "refunded_total": { + order.refunded_total = this.totalsService_.getRefundedTotal(order) + break + } + case "paid_total": { + order.paid_total = this.totalsService_.getPaidTotal(order) + break + } + case "refundable_amount": { + const paid_total = this.totalsService_.getPaidTotal(order) + const refunded_total = this.totalsService_.getRefundedTotal(order) + order.refundable_amount = paid_total - refunded_total + break + } + case "items.refundable": { + order.items = order.items.map((i) => ({ ...i, - quantity: i.quantity - (i.returned_quantity || 0), - }), - })) + refundable: this.totalsService_.getLineItemRefund(order, { + ...i, + quantity: i.quantity - (i.returned_quantity || 0), + }), + })) + break + } + case "swaps.additional_items.refundable": { + for (const s of order.swaps) { + s.additional_items = s.additional_items.map((i) => ({ + ...i, + refundable: this.totalsService_.getLineItemRefund(order, { + ...i, + quantity: i.quantity - (i.returned_quantity || 0), + }), + })) + } + break + } + case "claims.additional_items.refundable": { + for (const c of order.claims) { + c.additional_items = c.additional_items.map((i) => ({ + ...i, + refundable: this.totalsService_.getLineItemRefund(order, { + ...i, + quantity: i.quantity - (i.returned_quantity || 0), + }), + })) + } + break + } + default: { + break + } } } - - if ( - totalsFields.includes("claims.additional_items.refundable") && - order.claims && - order.claims.length - ) { - for (const c of order.claims) { - c.additional_items = c.additional_items.map((i) => ({ - ...i, - refundable: this.totalsService_.getLineItemRefund(order, { - ...i, - quantity: i.quantity - (i.returned_quantity || 0), - }), - })) - } - } - return order } diff --git a/packages/medusa/src/services/product-tax-rate.ts b/packages/medusa/src/services/product-tax-rate.ts new file mode 100644 index 0000000000..87e085e799 --- /dev/null +++ b/packages/medusa/src/services/product-tax-rate.ts @@ -0,0 +1,60 @@ +import { BaseService } from "medusa-interfaces" +import { EntityManager } from "typeorm" +import { ProductTaxRate } from "../models/product-tax-rate" +import { ProductTaxRateRepository } from "../repositories/product-tax-rate" +import { FindConfig } from "../types/common" +import { FilterableProductTaxRateProps } from "../types/product-tax-rate" + +/** + * Provides layer to manipulate product variants. + * @extends BaseService + */ +class ProductTaxRateService extends BaseService { + private manager_: EntityManager + private productTaxRateRepository_: typeof ProductTaxRateRepository + + constructor({ manager, productTaxRateRepository }) { + super() + + /** @private @const {EntityManager} */ + this.manager_ = manager + + /** @private @const {ProductVariantModel} */ + this.productTaxRateRepository_ = productTaxRateRepository + } + + withTransaction(transactionManager: EntityManager): ProductTaxRateService { + if (!transactionManager) { + return this + } + + const cloned = new ProductTaxRateService({ + manager: transactionManager, + productTaxRateRepository: this.productTaxRateRepository_, + }) + + cloned.transactionManager_ = transactionManager + + return cloned + } + + /** + * @param {FilterableProductVariantProps} selector - the query object for find + * @param {FindConfig} config - query config object for variant retrieval + * @return {Promise} the result of the find operation + */ + async list( + selector: FilterableProductTaxRateProps, + config: FindConfig = { relations: [], skip: 0, take: 20 } + ): Promise { + const pTaxRateRepo = this.manager_.getCustomRepository( + this.productTaxRateRepository_ + ) + + const query = this.buildQuery_(selector, config) + + return await pTaxRateRepo.find(query) + } +} + +export default ProductTaxRateService diff --git a/packages/medusa/src/services/product-type.ts b/packages/medusa/src/services/product-type.ts new file mode 100644 index 0000000000..b62bed4f76 --- /dev/null +++ b/packages/medusa/src/services/product-type.ts @@ -0,0 +1,99 @@ +import { MedusaError } from "medusa-core-utils" +import { BaseService } from "medusa-interfaces" +import { EntityManager } from "typeorm" +import { FindConfig } from "../types/common" +import { FilterableProductTypeProps } from "../types/product" +import { ProductType } from "../models/product-type" +import { ProductTypeRepository } from "../repositories/product-type" + +/** + * Provides layer to manipulate products. + * @extends BaseService + */ +class ProductTypeService extends BaseService { + private manager_: EntityManager + private typeRepository_: typeof ProductTypeRepository + constructor({ manager, productTypeRepository }) { + super() + + this.manager_ = manager + this.typeRepository_ = productTypeRepository + } + + withTransaction(transactionManager: EntityManager): ProductTypeService { + if (!transactionManager) { + return this + } + + const cloned = new ProductTypeService({ + manager: transactionManager, + productTypeRepository: this.typeRepository_, + }) + + cloned.transactionManager_ = transactionManager + cloned.manager_ = transactionManager + + return cloned + } + + /** + * Gets a product by id. + * Throws in case of DB Error and if product was not found. + * @param id - id of the product to get. + * @param config - object that defines what should be included in the + * query response + * @return {Promise} the result of the find one operation. + */ + async retrieve( + id: string, + config: FindConfig = {} + ): Promise { + const typeRepo = this.manager_.getCustomRepository(this.typeRepository_) + + const query = this.buildQuery_({ id }, config) + const type = await typeRepo.findOne(query) + + if (!type) { + throw new MedusaError( + MedusaError.Types.NOT_FOUND, + `Product with id: ${id} was not found` + ) + } + + return type + } + + /** + * Lists product types + * @param {Object} selector - the query object for find + * @param {Object} config - the config to be used for find + * @return {Promise} the result of the find operation + */ + async list( + selector: FilterableProductTypeProps = {}, + config: FindConfig = { skip: 0, take: 20 } + ): Promise { + const typeRepo = this.manager_.getCustomRepository(this.typeRepository_) + + const query = this.buildQuery_(selector, config) + return await typeRepo.find(query) + } + + /** + * Lists product tags and adds count. + * @param {Object} selector - the query object for find + * @param {Object} config - the config to be used for find + * @return {Promise} the result of the find operation + */ + async listAndCount( + selector: FilterableProductTypeProps = {}, + config: FindConfig = { skip: 0, take: 20 } + ): Promise<[ProductType[], number]> { + const typeRepo = this.manager_.getCustomRepository(this.typeRepository_) + + const query = this.buildQuery_(selector, config) + return await typeRepo.findAndCount(query) + } +} + +export default ProductTypeService diff --git a/packages/medusa/src/services/region.js b/packages/medusa/src/services/region.js index 9d265b51d4..5c4602fedf 100644 --- a/packages/medusa/src/services/region.js +++ b/packages/medusa/src/services/region.js @@ -22,6 +22,7 @@ class RegionService extends BaseService { currencyRepository, paymentProviderRepository, fulfillmentProviderRepository, + taxProviderRepository, paymentProviderService, fulfillmentProviderService, }) { @@ -54,6 +55,9 @@ class RegionService extends BaseService { /** @private @const {PaymentProviderService} */ this.paymentProviderService_ = paymentProviderService + /** @private @const {typeof TaxProviderService} */ + this.taxProviderRepository_ = taxProviderRepository + /** @private @const {FulfillmentProviderService} */ this.fulfillmentProviderService_ = fulfillmentProviderService } @@ -72,6 +76,7 @@ class RegionService extends BaseService { eventBusService: this.eventBus_, paymentProviderRepository: this.paymentProviderRepository_, paymentProviderService: this.paymentProviderService_, + taxProviderService: this.taxProviderService_, fulfillmentProviderRepository: this.fulfillmentProviderRepository_, fulfillmentProviderService: this.fulfillmentProviderService_, }) @@ -211,6 +216,9 @@ class RegionService extends BaseService { const fpRepository = this.manager_.getCustomRepository( this.fulfillmentProviderRepository_ ) + const tpRepository = this.manager_.getCustomRepository( + this.taxProviderRepository_ + ) if (region.tax_rate) { this.validateTaxRate_(region.tax_rate) @@ -226,6 +234,18 @@ class RegionService extends BaseService { }) } + if (region.tax_provider_id) { + const tp = await tpRepository.findOne({ + where: { id: region.tax_provider_id }, + }) + if (!tp) { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + "Tax provider not found" + ) + } + } + if (region.payment_providers) { region.payment_providers = await Promise.all( region.payment_providers.map(async (pId) => { diff --git a/packages/medusa/src/services/return.js b/packages/medusa/src/services/return.js index 1e9cfcd65d..439fb6b7e3 100644 --- a/packages/medusa/src/services/return.js +++ b/packages/medusa/src/services/return.js @@ -14,6 +14,7 @@ class ReturnService extends BaseService { returnItemRepository, shippingOptionService, returnReasonService, + taxProviderService, fulfillmentProviderService, inventoryService, orderService, @@ -35,6 +36,8 @@ class ReturnService extends BaseService { /** @private @const {ReturnItemRepository} */ this.lineItemService_ = lineItemService + this.taxProviderService_ = taxProviderService + /** @private @const {ShippingOptionService} */ this.shippingOptionService_ = shippingOptionService @@ -59,6 +62,7 @@ class ReturnService extends BaseService { totalsService: this.totalsService_, lineItemService: this.lineItemService_, returnRepository: this.returnRepository_, + taxProviderService: this.taxProviderService_, returnItemRepository: this.returnItemRepository_, shippingOptionService: this.shippingOptionService_, fulfillmentProviderService: this.fulfillmentProviderService_, @@ -335,9 +339,14 @@ class ReturnService extends BaseService { relations: [ "swaps", "swaps.additional_items", + "swaps.additional_items.tax_lines", "claims", "claims.additional_items", + "claims.additional_items.tax_lines", "items", + "items.tax_lines", + "region", + "region.tax_rates", ], }) @@ -347,18 +356,10 @@ class ReturnService extends BaseService { this.validateReturnLineItem_ ) - if (data.shipping_method) { - if (typeof data.shipping_method.price === "undefined") { - const opt = await this.shippingOptionService_.retrieve( - data.shipping_method.option_id - ) - data.shipping_method.price = opt.amount - } - } - let toRefund = data.refund_amount if (typeof toRefund !== "undefined") { - // refundable from order + // Merchant wants to do a custom refund amount; we check if amount is + // refundable const refundable = order.refundable_amount if (toRefund > refundable) { @@ -368,14 +369,8 @@ class ReturnService extends BaseService { ) } } else { + // Merchant hasn't specified refund amount so we calculate it toRefund = await this.totalsService_.getRefundTotal(order, returnLines) - - if (data.shipping_method) { - toRefund = Math.max( - 0, - toRefund - data.shipping_method.price * (1 + order.tax_rate / 100) - ) - } } const method = data.shipping_method @@ -416,7 +411,7 @@ class ReturnService extends BaseService { const result = await returnRepository.save(created) if (method) { - await this.shippingOptionService_ + const shippingMethod = await this.shippingOptionService_ .withTransaction(manager) .createShippingMethod( method.option_id, @@ -426,6 +421,26 @@ class ReturnService extends BaseService { return_id: result.id, } ) + + const calculationContext = + this.totalsService_.getCalculationContext(order) + + const taxLines = await this.taxProviderService_ + .withTransaction(manager) + .createShippingTaxLines(shippingMethod, calculationContext) + + const shippingTotal = + shippingMethod.price + + taxLines.reduce( + (acc, tl) => + acc + Math.round(shippingMethod.price * (tl.rate / 100)), + 0 + ) + + if (typeof data.refund_amount === "undefined") { + result.refund_amount = toRefund - shippingTotal + return await returnRepository.save(result) + } } return result @@ -438,6 +453,7 @@ class ReturnService extends BaseService { relations: [ "items", "shipping_method", + "shipping_method.tax_lines", "shipping_method.shipping_option", "swap", "claim_order", @@ -453,9 +469,12 @@ class ReturnService extends BaseService { const returnData = { ...returnOrder } - const items = await this.lineItemService_.list({ - id: returnOrder.items.map(({ item_id }) => item_id), - }) + const items = await this.lineItemService_.list( + { + id: returnOrder.items.map(({ item_id }) => item_id), + }, + { relations: ["tax_lines"] } + ) returnData.items = returnOrder.items.map((item) => { const found = items.find((i) => i.id === item.item_id) diff --git a/packages/medusa/src/services/shipping-option.js b/packages/medusa/src/services/shipping-option.js index 89232d08f8..dc13aee7af 100644 --- a/packages/medusa/src/services/shipping-option.js +++ b/packages/medusa/src/services/shipping-option.js @@ -13,7 +13,6 @@ class ShippingOptionService extends BaseService { shippingMethodRepository, fulfillmentProviderService, regionService, - totalsService, }) { super() @@ -34,9 +33,6 @@ class ShippingOptionService extends BaseService { /** @private @const {RegionService} */ this.regionService_ = regionService - - /** @private @const {TotalsService} */ - this.totalsService_ = totalsService } withTransaction(transactionManager) { @@ -51,7 +47,6 @@ class ShippingOptionService extends BaseService { shippingOptionRequirementRepository: this.requirementRepository_, fulfillmentProviderService: this.providerService_, regionService: this.regionService_, - totalsService: this.totalsService_, }) cloned.transactionManager_ = transactionManager @@ -132,6 +127,18 @@ class ShippingOptionService extends BaseService { return optRepo.find(query) } + /** + * @param {Object} selector - the query object for find + * @param {object} config - config object + * @return {Promise} the result of the find operation + */ + async listAndCount(selector, config = { skip: 0, take: 50 }) { + const optRepo = this.manager_.getCustomRepository(this.optionRepository_) + + const query = this.buildQuery_(selector, config) + return await optRepo.findAndCount(query) + } + /** * Gets a profile by id. * Throws in case of DB Error and if profile was not found. @@ -236,7 +243,7 @@ class ShippingOptionService extends BaseService { ) let methodPrice - if ("price" in config) { + if (typeof config.price === "number") { methodPrice = config.price } else { methodPrice = await this.getPrice_(option, validatedData, config.cart) diff --git a/packages/medusa/src/services/shipping-tax-rate.ts b/packages/medusa/src/services/shipping-tax-rate.ts new file mode 100644 index 0000000000..8c01187df1 --- /dev/null +++ b/packages/medusa/src/services/shipping-tax-rate.ts @@ -0,0 +1,61 @@ +import { BaseService } from "medusa-interfaces" +import { EntityManager } from "typeorm" +import { ShippingTaxRate } from "../models/shipping-tax-rate" +import { ShippingTaxRateRepository } from "../repositories/shipping-tax-rate" +import { FindConfig } from "../types/common" +import { FilterableShippingTaxRateProps } from "../types/shipping-tax-rate" + +/** + * Provides layer to manipulate Shipping variants. + * @extends BaseService + */ +class ShippingTaxRateService extends BaseService { + private manager_: EntityManager + private shippingTaxRateRepository_: typeof ShippingTaxRateRepository + + constructor({ manager, shippingTaxRateRepository }) { + super() + + /** @private @const {EntityManager} */ + this.manager_ = manager + + /** @private @const {ShippingVariantModel} */ + this.shippingTaxRateRepository_ = shippingTaxRateRepository + } + + withTransaction(transactionManager: EntityManager): ShippingTaxRateService { + if (!transactionManager) { + return this + } + + const cloned = new ShippingTaxRateService({ + manager: transactionManager, + shippingTaxRateRepository: this.ShippingTaxRateRepository_, + }) + + cloned.transactionManager_ = transactionManager + + return cloned + } + + /** + * Lists Shipping Tax Rates given a certain query. + * @param selector - the query object for find + * @param config - query config object for variant retrieval + * @return the result of the find operation + */ + async list( + selector: FilterableShippingTaxRateProps, + config: FindConfig = { relations: [], skip: 0, take: 20 } + ): Promise { + const sTaxRateRepo = this.manager_.getCustomRepository( + this.shippingTaxRateRepository_ + ) + + const query = this.buildQuery_(selector, config) + + return await sTaxRateRepo.find(query) + } +} + +export default ShippingTaxRateService diff --git a/packages/medusa/src/services/swap.js b/packages/medusa/src/services/swap.js index 15050d76ff..356b1ee038 100644 --- a/packages/medusa/src/services/swap.js +++ b/packages/medusa/src/services/swap.js @@ -27,6 +27,7 @@ class SwapService extends BaseService { returnService, lineItemService, paymentProviderService, + shippingMethodTaxLineRepository, shippingOptionService, fulfillmentService, orderService, @@ -71,6 +72,9 @@ class SwapService extends BaseService { /** @private @const {EventBusService} */ this.eventBus_ = eventBusService + /** @private @const {typeof ShippingMethodTaxLineRepository} */ + this.shippingTaxLineRepo_ = shippingMethodTaxLineRepository + /** @private @const {CustomShippingOptionService} */ this.customShippingOptionService_ = customShippingOptionService } @@ -88,6 +92,7 @@ class SwapService extends BaseService { totalsService: this.totalsService_, returnService: this.returnService_, lineItemService: this.lineItemService_, + shippingMethodTaxLineRepository: this.shippingTaxLineRepo_, paymentProviderService: this.paymentProviderService_, shippingOptionService: this.shippingOptionService_, orderService: this.orderService_, @@ -101,71 +106,67 @@ class SwapService extends BaseService { return cloned } - transformQueryForTotals_(config) { + transformQueryForCart_(config) { let { select, relations } = config - if (!select) { - return { - ...config, - totalsToSelect: [], + let cartSelects = null + let cartRelations = null + + if (typeof relations !== "undefined" && relations.includes("cart")) { + const [swapRelations, cartRels] = relations.reduce( + (acc, next) => { + if (next === "cart") { + return acc + } + + if (next.startsWith("cart.")) { + const [, ...rel] = next.split(".") + acc[1].push(rel.join(".")) + } else { + acc[0].push(next) + } + + return acc + }, + [[], []] + ) + + relations = swapRelations + cartRelations = cartRels + + let foundCartId = false + if (typeof select !== "undefined") { + const [swapSelects, cartSels] = select.reduce( + (acc, next) => { + if (next.startsWith("cart.")) { + const [, ...rel] = next.split(".") + acc[1].push(rel.join(".")) + } else { + if (next === "cart_id") { + foundCartId = true + } + acc[0].push(next) + } + + return acc + }, + [[], []] + ) + + select = foundCartId ? swapSelects : [...swapSelects, "cart_id"] + cartSelects = cartSels } } - const totalFields = [ - "cart.subtotal", - "cart.tax_total", - "cart.shipping_total", - "cart.discount_total", - "cart.gift_card_total", - "cart.total", - ] - - const totalsToSelect = select.filter((v) => totalFields.includes(v)) - if (totalsToSelect.length > 0) { - const relationSet = new Set(relations) - relationSet.add("cart") - relationSet.add("cart.items") - relationSet.add("cart.gift_cards") - relationSet.add("cart.discounts") - relationSet.add("cart.discounts.rule") - relationSet.add("cart.discounts.rule.valid_for") - relationSet.add("cart.shipping_methods") - relationSet.add("cart.region") - relations = [...relationSet] - - select = select.filter((v) => !totalFields.includes(v)) - } - return { ...config, relations, select, - totalsToSelect, + cartSelects, + cartRelations, } } - async decorateTotals_(cart, totalsFields = []) { - if (totalsFields.includes("cart.shipping_total")) { - cart.shipping_total = await this.totalsService_.getShippingTotal(cart) - } - if (totalsFields.includes("cart.discount_total")) { - cart.discount_total = await this.totalsService_.getDiscountTotal(cart) - } - if (totalsFields.includes("cart.tax_total")) { - cart.tax_total = await this.totalsService_.getTaxTotal(cart) - } - if (totalsFields.includes("cart.gift_card_total")) { - cart.gift_card_total = await this.totalsService_.getGiftCardTotal(cart) - } - if (totalsFields.includes("cart.subtotal")) { - cart.subtotal = await this.totalsService_.getSubtotal(cart) - } - if (totalsFields.includes("cart.total")) { - cart.total = await this.totalsService_.getTotal(cart) - } - return cart - } - /** * Retrieves a swap with the given id. * @param {string} id - the id of the swap to retrieve @@ -177,8 +178,8 @@ class SwapService extends BaseService { const validatedId = this.validateId_(id) - const { totalsToSelect, ...newConfig } = - this.transformQueryForTotals_(config) + const { cartSelects, cartRelations, ...newConfig } = + this.transformQueryForCart_(config) const query = this.buildQuery_({ id: validatedId }, newConfig) @@ -190,8 +191,11 @@ class SwapService extends BaseService { throw new MedusaError(MedusaError.Types.NOT_FOUND, "Swap was not found") } - if (rels && rels.includes("cart")) { - const cart = await this.decorateTotals_(swap.cart, totalsToSelect) + if (cartRelations || cartSelects) { + const cart = await this.cartService_.retrieve(swap.cart_id, { + select: cartSelects, + relations: cartRelations, + }) swap.cart = cart } @@ -548,6 +552,7 @@ class SwapService extends BaseService { "return_order", "return_order.items", "return_order.shipping_method", + "return_order.shipping_method.tax_lines", ], }) @@ -602,9 +607,12 @@ class SwapService extends BaseService { }) } - // If the swap has a return shipping method the price has to be added to the - // cart. + // If the swap has a return shipping method the price has to be added to + // the cart. if (swap.return_order && swap.return_order.shipping_method) { + const shippingTaxLineRepo = this.manager_.getCustomRepository( + this.shippingTaxLineRepo_ + ) await this.lineItemService_.withTransaction(manager).create({ cart_id: cart.id, title: "Return shipping", @@ -612,51 +620,26 @@ class SwapService extends BaseService { has_shipping: true, allow_discounts: false, unit_price: swap.return_order.shipping_method.price, - metadata: { - is_return_line: true, - }, + is_return: true, + tax_lines: swap.return_order.shipping_method.tax_lines.map((tl) => { + return shippingTaxLineRepo.create({ + name: tl.name, + code: tl.code, + rate: tl.rate, + metadata: tl.metadata, + }) + }), }) } - for (const r of swap.return_order.items) { - let allItems = [...order.items] - - if (order.swaps && order.swaps.length) { - for (const s of order.swaps) { - allItems = [...allItems, ...s.additional_items] - } - } - - if (order.claims && order.claims.length) { - for (const c of order.claims) { - allItems = [...allItems, ...c.additional_items] - } - } - - const lineItem = allItems.find((i) => i.id === r.item_id) - - const toCreate = { - cart_id: cart.id, - thumbnail: lineItem.thumbnail, - title: lineItem.title, - variant_id: lineItem.variant_id, - unit_price: -1 * lineItem.unit_price, - quantity: r.quantity, - allow_discounts: lineItem.allow_discounts, - metadata: { - ...lineItem.metadata, - is_return_line: true, - }, - } - - await this.lineItemService_.withTransaction(manager).create(toCreate) - } + await this.lineItemService_ + .withTransaction(manager) + .createReturnLines(swap.return_order.id, cart.id) swap.cart_id = cart.id const swapRepo = manager.getCustomRepository(this.swapRepository_) - const result = await swapRepo.save(swap) - return result + return await swapRepo.save(swap) }) } @@ -664,18 +647,16 @@ class SwapService extends BaseService { *@param {string} swapId - The id of the swap */ async registerCartCompletion(swapId) { - return this.atomicPhase_(async (manager) => { + return await this.atomicPhase_(async (manager) => { const swap = await this.retrieve(swapId, { - relations: [ - "cart", - "cart.region", - "cart.shipping_methods", - "cart.shipping_address", - "cart.items", - "cart.discounts", - "cart.discounts.rule", - "cart.payment", - "cart.gift_cards", + select: [ + "id", + "order_id", + "no_notification", + "allow_backorder", + "canceled_at", + "confirmed_at", + "cart_id", ], }) @@ -691,10 +672,14 @@ class SwapService extends BaseService { ) } - const cart = swap.cart + const cart = await this.cartService_.retrieve(swap.cart_id, { + select: ["total"], + relations: ["payment", "shipping_methods", "items"], + }) + const { payment } = cart - const items = swap.cart.items + const items = cart.items if (!swap.allow_backorder) { for (const item of items) { @@ -716,7 +701,7 @@ class SwapService extends BaseService { } } - const total = await this.totalsService_.getTotal(cart) + const total = cart.total if (total > 0) { if (!payment) { @@ -785,49 +770,6 @@ class SwapService extends BaseService { }) } - /** - * Registers the return associated with a swap as received. If the return - * is received with mismatching return items the swap's status will be updated - * to requires_action. - * @param {string} swapId - the id of the swap to receive. - * @param {Array} returnItems - the return items that have been returned - * @return {Promise} the resulting swap, with an updated return and - * status. - */ - async receiveReturn(swapId, returnItems) { - return this.atomicPhase_(async (manager) => { - const swap = await this.retrieve(swapId, { relations: ["return_order"] }) - - if (swap.canceled_at) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "Canceled swap cannot be registered as received" - ) - } - - const returnId = swap.return_order && swap.return_order.id - if (!returnId) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Swap has no return request" - ) - } - - const updatedRet = await this.returnService_ - .withTransaction(manager) - .receiveReturn(returnId, returnItems, undefined, false) - - if (updatedRet.status === "requires_action") { - const swapRepo = manager.getCustomRepository(this.swapRepository_) - swap.fulfillment_status = "requires_action" - const result = await swapRepo.save(swap) - return result - } - - return this.retrieve(swapId) - }) - } - /** * Cancels a given swap if possible. A swap can only be canceled if all * related returns, fulfillments, and payments have been canceled. If a swap @@ -908,8 +850,11 @@ class SwapService extends BaseService { "payment", "shipping_address", "additional_items", + "additional_items.tax_lines", "shipping_methods", + "shipping_methods.tax_lines", "order", + "order.region", "order.billing_address", "order.discounts", "order.discounts.rule", @@ -956,6 +901,7 @@ class SwapService extends BaseService { currency_code: order.currency_code, tax_rate: order.tax_rate, region_id: order.region_id, + region: order.region, display_id: order.display_id, billing_address: order.billing_address, items: swap.additional_items, diff --git a/packages/medusa/src/services/system-tax.ts b/packages/medusa/src/services/system-tax.ts new file mode 100644 index 0000000000..7bcab612d5 --- /dev/null +++ b/packages/medusa/src/services/system-tax.ts @@ -0,0 +1,47 @@ +import { BaseService } from "medusa-interfaces" + +import { + ITaxService, + ItemTaxCalculationLine, + ShippingTaxCalculationLine, + TaxCalculationContext, +} from "../interfaces/tax-service" +import { ProviderTaxLine } from "../types/tax-service" + +class SystemTaxService extends BaseService implements ITaxService { + static identifier = "system" + + constructor() { + super() + } + + async getTaxLines( + itemLines: ItemTaxCalculationLine[], + shippingLines: ShippingTaxCalculationLine[], + context: TaxCalculationContext // eslint-disable-line + ): Promise { + let taxLines: ProviderTaxLine[] = itemLines.flatMap((l) => { + return l.rates.map((r) => ({ + rate: r.rate || 0, + name: r.name, + code: r.code, + item_id: l.item.id, + })) + }) + + taxLines = taxLines.concat( + shippingLines.flatMap((l) => { + return l.rates.map((r) => ({ + rate: r.rate || 0, + name: r.name, + code: r.code, + shipping_method_id: l.shipping_method.id, + })) + }) + ) + + return taxLines + } +} + +export default SystemTaxService diff --git a/packages/medusa/src/services/tax-provider.ts b/packages/medusa/src/services/tax-provider.ts new file mode 100644 index 0000000000..b0ae0a3b07 --- /dev/null +++ b/packages/medusa/src/services/tax-provider.ts @@ -0,0 +1,433 @@ +import { MedusaError } from "medusa-core-utils" +import { AwilixContainer } from "awilix" +import { BaseService } from "medusa-interfaces" +import { EntityManager } from "typeorm" +import Redis from "ioredis" + +import { LineItemTaxLineRepository } from "../repositories/line-item-tax-line" +import { ShippingMethodTaxLineRepository } from "../repositories/shipping-method-tax-line" +import { TaxProviderRepository } from "../repositories/tax-provider" +import { LineItemTaxLine } from "../models/line-item-tax-line" +import { TaxProvider } from "../models/tax-provider" +import { LineItem } from "../models/line-item" +import { ShippingMethodTaxLine } from "../models/shipping-method-tax-line" +import { ShippingMethod } from "../models/shipping-method" +import { Region } from "../models/region" +import { Cart } from "../models/cart" +import { isCart } from "../types/cart" +import { + ITaxService, + ItemTaxCalculationLine, + TaxCalculationContext, +} from "../interfaces/tax-service" + +import { TaxServiceRate } from "../types/tax-service" + +import TaxRateService from "./tax-rate" + +const CACHE_TIME = 30 // seconds + +/** + * Finds tax providers and assists in tax related operations. + */ +class TaxProviderService extends BaseService { + private container_: AwilixContainer + private manager_: EntityManager + private transactionManager_: EntityManager + private taxRateService_: TaxRateService + private taxLineRepo_: typeof LineItemTaxLineRepository + private smTaxLineRepo_: typeof ShippingMethodTaxLineRepository + private taxProviderRepo_: typeof TaxProviderRepository + private redis_: Redis + + constructor(container: AwilixContainer) { + super() + + this.container_ = container + this.taxLineRepo_ = container["lineItemTaxLineRepository"] + this.smTaxLineRepo_ = container["shippingMethodTaxLineRepository"] + this.taxRateService_ = container["taxRateService"] + this.eventBus_ = container["eventBusService"] + this.taxProviderRepo_ = container["taxProviderRepository"] + this.manager_ = container["manager"] + this.redis_ = container["redisClient"] + } + + withTransaction(transactionManager: EntityManager): TaxProviderService { + if (!transactionManager) { + return this + } + + const cloned = new TaxProviderService(this.container_) + + cloned.transactionManager_ = transactionManager + cloned.manager_ = transactionManager + + return cloned + } + + async list(): Promise { + const tpRepo = this.manager_.getCustomRepository(this.taxProviderRepo_) + return tpRepo.find({}) + } + + /** + * Retrieves the relevant tax provider for the given region. + * @param region - the region to get tax provider for. + * @return the region specific tax provider + */ + retrieveProvider(region: Region): ITaxService { + let provider: ITaxService + if (region.tax_provider_id) { + provider = this.container_[`tp_${region.tax_provider_id}`] + } else { + provider = this.container_["systemTaxService"] + } + + if (!provider) { + throw new MedusaError( + MedusaError.Types.NOT_FOUND, + `Could not find a tax provider with id: ${region.tax_provider_id}` + ) + } + + return provider + } + + /** + * Persists the tax lines relevant for an order to the database. + * @param cartOrLineItems - the cart or line items to create tax lines for + * @param calculationContext - the calculation context to get tax lines by + * @return the newly created tax lines + */ + async createTaxLines( + cartOrLineItems: Cart | LineItem[], + calculationContext: TaxCalculationContext + ): Promise<(ShippingMethodTaxLine | LineItemTaxLine)[]> { + let taxLines: (ShippingMethodTaxLine | LineItemTaxLine)[] = [] + if (isCart(cartOrLineItems)) { + taxLines = await this.getTaxLines( + cartOrLineItems.items, + calculationContext + ) + } else { + taxLines = await this.getTaxLines(cartOrLineItems, calculationContext) + } + + return this.manager_.save(taxLines) + } + + /** + * Persists the tax lines relevant for a shipping method to the database. Used + * for return shipping methods. + * @param shippingMethod - the shipping method to create tax lines for + * @param calculationContext - the calculation context to get tax lines by + * @return the newly created tax lines + */ + async createShippingTaxLines( + shippingMethod: ShippingMethod, + calculationContext: TaxCalculationContext + ): Promise<(ShippingMethodTaxLine | LineItemTaxLine)[]> { + const taxLines = await this.getShippingTaxLines( + shippingMethod, + calculationContext + ) + return this.manager_.save(taxLines) + } + + /** + * Gets the relevant tax lines for a shipping method. Note: this method + * doesn't persist the tax lines. Use createShippingTaxLines if you wish to + * persist the tax lines to the DB layer. + * @param shippingMethod - the shipping method to get tax lines for + * @param calculationContext - the calculation context to get tax lines by + * @return the computed tax lines + */ + async getShippingTaxLines( + shippingMethod: ShippingMethod, + calculationContext: TaxCalculationContext + ): Promise { + const calculationLines = [ + { + shipping_method: shippingMethod, + rates: await this.getRegionRatesForShipping( + shippingMethod.shipping_option_id, + calculationContext.region + ), + }, + ] + + const taxProvider = this.retrieveProvider(calculationContext.region) + const providerLines = await taxProvider.getTaxLines( + [], + calculationLines, + calculationContext + ) + + const smTaxLineRepo = this.manager_.getCustomRepository(this.smTaxLineRepo_) + + // .create only creates entities nothing is persisted in DB + return providerLines.map((pl) => { + if (!("shipping_method_id" in pl)) { + throw new MedusaError( + MedusaError.Types.UNEXPECTED_STATE, + "Expected only shipping method tax lines" + ) + } + + return smTaxLineRepo.create({ + shipping_method_id: pl.shipping_method_id, + rate: pl.rate, + name: pl.name, + code: pl.code, + metadata: pl.metadata, + }) + }) + } + + /** + * Gets the relevant tax lines for an order or cart. If an order is provided + * the order's tax lines will be returned. If a cart is provided the tax lines + * will be computed from the tax rules and potentially a 3rd party tax plugin. + * Note: this method doesn't persist the tax lines. Use createTaxLines if you + * wish to persist the tax lines to the DB layer. + * @param lineItems - the cart or order to get tax lines for + * @param calculationContext - the calculation context to get tax lines by + * @return the computed tax lines + */ + async getTaxLines( + lineItems: LineItem[], + calculationContext: TaxCalculationContext + ): Promise<(ShippingMethodTaxLine | LineItemTaxLine)[]> { + const calculationLines = await Promise.all( + lineItems.map(async (l) => { + if (l.is_return) { + return null + } + + if (l.variant && l.variant.product_id) { + return { + item: l, + rates: await this.getRegionRatesForProduct( + l.variant.product_id, + calculationContext.region + ), + } + } + + /* + * If the line item is custom and therefore not associated with a + * product we assume no taxes - we should consider adding rate overrides + * to custom lines at some point + */ + return { + item: l, + rates: [], + } + }) + ) + + const shippingCalculationLines = await Promise.all( + calculationContext.shipping_methods.map(async (sm) => { + return { + shipping_method: sm, + rates: await this.getRegionRatesForShipping( + sm.shipping_option_id, + calculationContext.region + ), + } + }) + ) + + const taxProvider = this.retrieveProvider(calculationContext.region) + const providerLines = await taxProvider.getTaxLines( + calculationLines.filter((v) => v !== null) as ItemTaxCalculationLine[], + shippingCalculationLines, + calculationContext + ) + + const liTaxLineRepo = this.manager_.getCustomRepository(this.taxLineRepo_) + const smTaxLineRepo = this.manager_.getCustomRepository(this.smTaxLineRepo_) + + // .create only creates entities nothing is persisted in DB + return providerLines.map((pl) => { + if ("shipping_method_id" in pl) { + return smTaxLineRepo.create({ + shipping_method_id: pl.shipping_method_id, + rate: pl.rate, + name: pl.name, + code: pl.code, + metadata: pl.metadata, + }) + } + + if (!("item_id" in pl)) { + throw new MedusaError( + MedusaError.Types.UNEXPECTED_STATE, + "Tax Provider returned invalid tax lines" + ) + } + + return liTaxLineRepo.create({ + item_id: pl.item_id, + rate: pl.rate, + name: pl.name, + code: pl.code, + metadata: pl.metadata, + }) + }) + } + + /** + * Gets the tax rates configured for a shipping option. The rates are cached + * between calls. + * @param optionId - the option id of the shipping method. + * @param region - the region to get configured rates for. + * @return the tax rates configured for the shipping option. + */ + async getRegionRatesForShipping( + optionId: string, + region: Region + ): Promise { + const cacheHit = await this.getCacheEntry(optionId, region.id) + if (cacheHit) { + return cacheHit + } + + let toReturn: TaxServiceRate[] = [] + const optionRates = await this.taxRateService_.listByShippingOption( + optionId, + { region_id: region.id } + ) + + if (optionRates.length > 0) { + toReturn = optionRates.map((pr) => { + return { + rate: pr.rate, + name: pr.name, + code: pr.code, + } + }) + } + + if (toReturn.length === 0) { + toReturn = [ + { + rate: region.tax_rate, + name: "default", + code: "default", + }, + ] + } + + await this.setCache(optionId, region.id, toReturn) + + return toReturn + } + + /** + * Gets the tax rates configured for a product. The rates are cached between + * calls. + * @param productId - the product id to get rates for + * @param region - the region to get configured rates for. + * @return the tax rates configured for the shipping option. + */ + async getRegionRatesForProduct( + productId: string, + region: Region + ): Promise { + const cacheHit = await this.getCacheEntry(productId, region.id) + if (cacheHit) { + return cacheHit + } + + let toReturn: TaxServiceRate[] = [] + const productRates = await this.taxRateService_.listByProduct(productId, { + region_id: region.id, + }) + + if (productRates.length > 0) { + toReturn = productRates.map((pr) => { + return { + rate: pr.rate, + name: pr.name, + code: pr.code, + } + }) + } + + if (toReturn.length === 0) { + toReturn = [ + { + rate: region.tax_rate, + name: "default", + code: "default", + }, + ] + } + + await this.setCache(productId, region.id, toReturn) + + return toReturn + } + + /** + * The cache key to get cache hits by. + * @param productId - the product id to cache + * @param regionId - the region id to cache + * @return the cache key to use for the id set + */ + private getCacheKey(productId: string, regionId: string): string { + return `txrtcache:${productId}:${regionId}` + } + + /** + * Sets the cache results for a set of ids + * @param productId - the product id to cache + * @param regionId - the region id to cache + * @param value - tax rates to cache + * @return promise that resolves after the cache has been set + */ + private async setCache( + productId: string, + regionId: string, + value: TaxServiceRate[] + ): Promise { + const cacheKey = this.getCacheKey(productId, regionId) + return await this.redis_.set( + cacheKey, + JSON.stringify(value), + "EX", + CACHE_TIME + ) + } + + /** + * Gets the cache results for a set of ids + * @param productId - the product id to cache + * @param regionId - the region id to cache + * @return the cached result or null + */ + private async getCacheEntry( + productId: string, + regionId: string + ): Promise { + const cacheKey = this.getCacheKey(productId, regionId) + + try { + const cacheHit = await this.redis_.get(cacheKey) + if (cacheHit) { + // TODO: Validate that cache has correct data + const parsedResults = JSON.parse(cacheHit) as TaxServiceRate[] + return parsedResults + } + } catch (_) { + // noop - cache parse failed + await this.redis_.del(cacheKey) + } + + return null + } +} + +export default TaxProviderService diff --git a/packages/medusa/src/services/tax-rate.ts b/packages/medusa/src/services/tax-rate.ts new file mode 100644 index 0000000000..49e465e8f1 --- /dev/null +++ b/packages/medusa/src/services/tax-rate.ts @@ -0,0 +1,343 @@ +import { BaseService } from "medusa-interfaces" +import { EntityManager } from "typeorm" +import { MedusaError } from "medusa-core-utils" +import { TaxRate } from "../models/tax-rate" +import { ShippingTaxRate } from "../models/shipping-tax-rate" +import { ProductTaxRate } from "../models/product-tax-rate" +import { ProductTypeTaxRate } from "../models/product-type-tax-rate" +import { TaxRateRepository } from "../repositories/tax-rate" +import ProductService from "../services/product" +import ProductTypeService from "../services/product-type" +import ShippingOptionService from "../services/shipping-option" +import { FindConfig } from "../types/common" +import { + CreateTaxRateInput, + UpdateTaxRateInput, + TaxRateListByConfig, + FilterableTaxRateProps, +} from "../types/tax-rate" + +class TaxRateService extends BaseService { + private manager_: EntityManager + private productService_: ProductService + private productTypeService_: ProductTypeService + private shippingOptionService_: ShippingOptionService + private taxRateRepository_: typeof TaxRateRepository + + constructor({ + manager, + productService, + productTypeService, + shippingOptionService, + taxRateRepository, + }) { + super() + + this.manager_ = manager + this.taxRateRepository_ = taxRateRepository + this.productService_ = productService + this.productTypeService_ = productTypeService + this.shippingOptionService_ = shippingOptionService + } + + withTransaction(transactionManager: EntityManager): TaxRateService { + if (!transactionManager) { + return this + } + + const cloned = new TaxRateService({ + manager: transactionManager, + taxRateRepository: this.taxRateRepository_, + productService: this.productService_, + productTypeService: this.productTypeService_, + shippingOptionService: this.shippingOptionService_, + }) + + cloned.transactionManager_ = transactionManager + cloned.manager_ = transactionManager + + return cloned + } + + async list( + selector: FilterableTaxRateProps, + config: FindConfig = {} + ): Promise { + const taxRateRepo = this.manager_.getCustomRepository( + this.taxRateRepository_ + ) + const query = this.buildQuery_(selector, config) + return await taxRateRepo.findWithResolution(query) + } + + async listAndCount( + selector: FilterableTaxRateProps, + config: FindConfig = {} + ): Promise<[TaxRate[], number]> { + const taxRateRepo = this.manager_.getCustomRepository( + this.taxRateRepository_ + ) + const query = this.buildQuery_(selector, config) + return await taxRateRepo.findAndCountWithResolution(query) + } + + async retrieve( + id: string, + config: FindConfig = {} + ): Promise { + return await this.atomicPhase_(async (manager: EntityManager) => { + const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + const query = this.buildQuery_({ id }, config) + + const taxRate = await taxRateRepo.findOneWithResolution(query) + if (!taxRate) { + throw new MedusaError( + MedusaError.Types.NOT_FOUND, + `TaxRate with ${id} was not found` + ) + } + + return taxRate + }) + } + + async create(data: CreateTaxRateInput): Promise { + return await this.atomicPhase_(async (manager: EntityManager) => { + const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + + if (typeof data.region_id === "undefined") { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + "TaxRates must belong to a Region" + ) + } + + const taxRate = taxRateRepo.create(data) + return await taxRateRepo.save(taxRate) + }) + } + + async update(id: string, data: UpdateTaxRateInput): Promise { + return await this.atomicPhase_(async (manager: EntityManager) => { + const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + const taxRate = await this.retrieve(id) + + for (const [k, v] of Object.entries(data)) { + if (typeof v !== "undefined") { + taxRate[k] = v + } + } + + return await taxRateRepo.save(taxRate) + }) + } + + async delete(id: string | string[]): Promise { + return await this.atomicPhase_(async (manager: EntityManager) => { + const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + const query = this.buildQuery_({ id }) + await taxRateRepo.delete(query.where) + }) + } + + async removeFromProduct( + id: string, + productIds: string | string[] + ): Promise { + return await this.atomicPhase_(async (manager: EntityManager) => { + const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + + let ids: string[] + if (typeof productIds === "string") { + ids = [productIds] + } else { + ids = productIds + } + + await taxRateRepo.removeFromProduct(id, ids) + }) + } + + async removeFromProductType( + id: string, + typeIds: string | string[] + ): Promise { + return await this.atomicPhase_(async (manager: EntityManager) => { + const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + + let ids: string[] + if (typeof typeIds === "string") { + ids = [typeIds] + } else { + ids = typeIds + } + + await taxRateRepo.removeFromProductType(id, ids) + }) + } + + async removeFromShippingOption( + id: string, + optionIds: string | string[] + ): Promise { + return await this.atomicPhase_(async (manager: EntityManager) => { + const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + + let ids: string[] + if (typeof optionIds === "string") { + ids = [optionIds] + } else { + ids = optionIds + } + + await taxRateRepo.removeFromShippingOption(id, ids) + }) + } + + async addToProduct( + id: string, + productIds: string | string[], + replace = false + ): Promise { + let ids: string[] + if (typeof productIds === "string") { + ids = [productIds] + } else { + ids = productIds + } + + const result = await this.atomicPhase_( + async (manager: EntityManager) => { + const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + return await taxRateRepo.addToProduct(id, ids, replace) + }, + // eslint-disable-next-line + async (err: any) => { + if (err.code === "23503") { + // A foreign key constraint failed meaning some thing doesn't exist + // either it is a product or the tax rate itself. Using Promise.all + // will try to retrieve all of the resources and will fail when + // something is not found. + await Promise.all([ + this.retrieve(id, { select: ["id"] }), + ...ids.map((pId) => + this.productService_.retrieve(pId, { select: ["id"] }) + ), + ]) + } + } + ) + return result + } + + async addToProductType( + id: string, + productTypeIds: string | string[], + replace = false + ): Promise { + let ids: string[] + if (typeof productTypeIds === "string") { + ids = [productTypeIds] + } else { + ids = productTypeIds + } + + return await this.atomicPhase_( + async (manager: EntityManager) => { + const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + return await taxRateRepo.addToProductType(id, ids, replace) + }, + // eslint-disable-next-line + async (err: any) => { + if (err.code === "23503") { + // A foreign key constraint failed meaning some thing doesn't exist + // either it is a product or the tax rate itself. Using Promise.all + // will try to retrieve all of the resources and will fail when + // something is not found. + await Promise.all([ + this.retrieve(id, { + select: ["id"], + }) as Promise, + ...ids.map( + (pId) => + this.productTypeService_.retrieve(pId, { + select: ["id"], + }) as Promise + ), + ]) + } + } + ) + } + + async addToShippingOption( + id: string, + optionIds: string | string[], + replace = false + ): Promise { + let ids: string[] + if (typeof optionIds === "string") { + ids = [optionIds] + } else { + ids = optionIds + } + + return await this.atomicPhase_( + async (manager: EntityManager) => { + const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + const taxRate = await this.retrieve(id, { select: ["id", "region_id"] }) + const options = await this.shippingOptionService_.list( + { id: ids }, + { select: ["id", "region_id"] } + ) + for (const o of options) { + if (o.region_id !== taxRate.region_id) { + throw new MedusaError( + MedusaError.Types.NOT_ALLOWED, + `Shipping Option and Tax Rate must belong to the same Region to be associated. Shipping Option with id: ${o.id} belongs to Region with id: ${o.region_id} and Tax Rate with id: ${taxRate.id} belongs to Region with id: ${taxRate.region_id}` + ) + } + } + return await taxRateRepo.addToShippingOption(id, ids, replace) + }, + // eslint-disable-next-line + async (err: any) => { + if (err.code === "23503") { + // A foreign key constraint failed meaning some thing doesn't exist + // either it is a product or the tax rate itself. Using Promise.all + // will try to retrieve all of the resources and will fail when + // something is not found. + await Promise.all([ + this.retrieve(id, { select: ["id"] }), + ...ids.map((sId) => + this.shippingOptionService_.retrieve(sId, { select: ["id"] }) + ), + ]) + } + } + ) + } + + async listByProduct( + productId: string, + config: TaxRateListByConfig + ): Promise { + // Check both ProductTaxRate + ProductTypeTaxRate + return await this.atomicPhase_(async (manager: EntityManager) => { + const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + return await taxRateRepo.listByProduct(productId, config) + }) + } + + async listByShippingOption( + shippingOptionId: string, + config: TaxRateListByConfig + ): Promise { + return await this.atomicPhase_(async (manager: EntityManager) => { + const taxRateRepo = manager.getCustomRepository(this.taxRateRepository_) + return await taxRateRepo.listByShippingOption(shippingOptionId, config) + }) + } +} + +export default TaxRateService diff --git a/packages/medusa/src/services/totals.js b/packages/medusa/src/services/totals.js deleted file mode 100644 index 2aa3a4fcf1..0000000000 --- a/packages/medusa/src/services/totals.js +++ /dev/null @@ -1,389 +0,0 @@ -import _ from "lodash" -import { BaseService } from "medusa-interfaces" -import { MedusaError } from "medusa-core-utils" - -/** - * A service that calculates total and subtotals for orders, carts etc.. - * @implements {BaseService} - */ -class TotalsService extends BaseService { - constructor() { - super() - } - - /** - * Calculates subtotal of a given cart or order. - * @param {object} object - object to calculate total for - * @return {int} the calculated subtotal - */ - getTotal(object) { - const subtotal = this.getSubtotal(object) - const taxTotal = this.getTaxTotal(object) - const discountTotal = this.getDiscountTotal(object) - const giftCardTotal = this.getGiftCardTotal(object) - const shippingTotal = this.getShippingTotal(object) - - return subtotal + taxTotal + shippingTotal - discountTotal - giftCardTotal - } - - getPaidTotal(order) { - const total = order.payments?.reduce((acc, next) => { - acc += next.amount - return acc - }, 0) - - return total - } - - getSwapTotal(order) { - let swapTotal = 0 - if (order.swaps && order.swaps.length) { - for (const s of order.swaps) { - swapTotal = swapTotal + s.difference_due - } - } - - return swapTotal - } - - /** - * Calculates subtotal of a given cart or order. - * @param {(Cart|Order)} object - cart or order to calculate subtotal for - * @param {Object} opts - options - * @return {int} the calculated subtotal - */ - getSubtotal(object, opts = {}) { - let subtotal = 0 - if (!object.items) { - return subtotal - } - - object.items.map((item) => { - if (opts.excludeNonDiscounts) { - if (item.allow_discounts) { - subtotal += item.unit_price * item.quantity - } - } else { - subtotal += item.unit_price * item.quantity - } - }) - - return this.rounded(subtotal) - } - - /** - * Calculates shipping total - * @param {Cart | Object} object - cart or order to calculate subtotal for - * @return {int} shipping total - */ - getShippingTotal(object) { - const { shipping_methods } = object - return shipping_methods.reduce((acc, next) => { - return acc + next.price - }, 0) - } - - /** - * Calculates tax total - * Currently based on the Danish tax system - * @param {Cart | Object} object - cart or order to calculate subtotal for - * @return {int} tax total - */ - getTaxTotal(object) { - const subtotal = this.getSubtotal(object) - const shippingTotal = this.getShippingTotal(object) - const discountTotal = this.getDiscountTotal(object) - const giftCardTotal = this.getGiftCardTotal(object) - const tax_rate = - typeof object.tax_rate !== "undefined" - ? object.tax_rate - : object.region.tax_rate - return this.rounded( - (subtotal - discountTotal - giftCardTotal + shippingTotal) * - (tax_rate / 100) - ) - } - - getRefundedTotal(object) { - if (!object.refunds) { - return 0 - } - - const total = object.refunds.reduce((acc, next) => acc + next.amount, 0) - return this.rounded(total) - } - - getLineItemRefund(object, lineItem) { - const { discounts } = object - const tax_rate = - typeof object.tax_rate !== "undefined" - ? object.tax_rate - : object.region.tax_rate - const taxRate = (tax_rate || 0) / 100 - - const discount = discounts.find(({ rule }) => rule.type !== "free_shipping") - - if (!discount || !lineItem.allow_discounts) { - return lineItem.unit_price * lineItem.quantity * (1 + taxRate) - } - - const lineDiscounts = this.getLineDiscounts(object, discount) - const discountedLine = lineDiscounts.find( - (line) => line.item.id === lineItem.id - ) - - const discountAmount = - (discountedLine.amount / discountedLine.item.quantity) * lineItem.quantity - - return this.rounded( - (lineItem.unit_price * lineItem.quantity - discountAmount) * (1 + taxRate) - ) - } - - /** - * Calculates refund total of line items. - * If any of the items to return have been discounted, we need to - * apply the discount again before refunding them. - * @param {Order} order - cart or order to calculate subtotal for - * @param {[LineItem]} lineItems - - * @return {int} the calculated subtotal - */ - getRefundTotal(order, lineItems) { - let itemIds = order.items.map((i) => i.id) - - // in case we swap a swap, we need to include swap items - if (order.swaps && order.swaps.length) { - for (const s of order.swaps) { - const swapItemIds = s.additional_items.map((el) => el.id) - itemIds = [...itemIds, ...swapItemIds] - } - } - - if (order.claims && order.claims.length) { - for (const c of order.claims) { - const claimItemIds = c.additional_items.map((el) => el.id) - itemIds = [...itemIds, ...claimItemIds] - } - } - - const refunds = lineItems.map((i) => { - if (!itemIds.includes(i.id)) { - throw new MedusaError( - MedusaError.Types.INVALID_DATA, - "Line item does not exist on order" - ) - } - - return this.getLineItemRefund(order, i) - }) - - return this.rounded(refunds.reduce((acc, next) => acc + next, 0)) - } - - /** - * Calculates either fixed or percentage discount of a variant - * @param {string} lineItem - id of line item - * @param {string} variant - id of variant in line item - * @param {int} variantPrice - price of the variant based on region - * @param {int} value - discount value - * @param {string} discountType - the type of discount (fixed or percentage) - * @return {{ string, string, int }} triples of lineitem, variant and - * applied discount - */ - calculateDiscount_(lineItem, variant, variantPrice, value, discountType) { - if (!lineItem.allow_discounts) { - return { - lineItem, - variant, - amount: 0, - } - } - if (discountType === "percentage") { - return { - lineItem, - variant, - amount: ((variantPrice * lineItem.quantity) / 100) * value, - } - } else { - return { - lineItem, - variant, - amount: - value >= variantPrice * lineItem.quantity - ? variantPrice * lineItem.quantity - : value * lineItem.quantity, - } - } - } - - /** - * If the rule of a discount has allocation="item", then we need - * to calculate discount on each item in the cart. Furthermore, we need to - * make sure to only apply the discount on valid variants. And finally we - * return ether an array of percentages discounts or fixed discounts - * alongside the variant on which the discount was applied. - * @param {Discount} discount - the discount to which we do the calculation - * @param {Cart} cart - the cart to calculate discounts for - * @return {[{ string, string, int }]} array of triples of lineitem, variant - * and applied discount - */ - getAllocationItemDiscounts(discount, cart) { - const discounts = [] - for (const item of cart.items) { - if (discount.rule.valid_for?.length > 0) { - discount.rule.valid_for.map(({ id }) => { - if (item.variant.product_id === id) { - discounts.push( - this.calculateDiscount_( - item, - item.variant.id, - item.unit_price, - discount.rule.value, - discount.rule.type - ) - ) - } - }) - } - } - return discounts - } - - getLineDiscounts(cart, discount) { - const subtotal = this.getSubtotal(cart, { excludeNonDiscounts: true }) - - let merged = [...cart.items] - - // merge items from order with items from order swaps - if (cart.swaps && cart.swaps.length) { - for (const s of cart.swaps) { - merged = [...merged, ...s.additional_items] - } - } - - if (cart.claims && cart.claims.length) { - for (const c of cart.claims) { - merged = [...merged, ...c.additional_items] - } - } - - const { type, allocation, value } = discount.rule - if (allocation === "total") { - let percentage = 0 - if (type === "percentage") { - percentage = value / 100 - } else if (type === "fixed") { - // If the fixed discount exceeds the subtotal we should - // calculate a 100% discount - const nominator = Math.min(value, subtotal) - percentage = nominator / subtotal - } - - return merged.map((item) => { - const lineTotal = item.unit_price * item.quantity - - return { - item, - amount: lineTotal * percentage, - } - }) - } else if (allocation === "item") { - const allocationDiscounts = this.getAllocationItemDiscounts( - discount, - cart, - type - ) - return merged.map((item) => { - const discounted = allocationDiscounts.find( - (a) => a.lineItem.id === item.id - ) - return { - item, - amount: discounted ? discounted.amount : 0, - } - }) - } - - return merged.map((i) => ({ item: i, amount: 0 })) - } - - getGiftCardTotal(cart) { - const giftCardable = this.getSubtotal(cart) - this.getDiscountTotal(cart) - - if (cart.gift_card_transactions) { - return cart.gift_card_transactions.reduce( - (acc, next) => acc + next.amount, - 0 - ) - } - - if (!cart.gift_cards || !cart.gift_cards.length) { - return 0 - } - - const toReturn = cart.gift_cards.reduce( - (acc, next) => acc + next.balance, - 0 - ) - return Math.min(giftCardable, toReturn) - } - - /** - * Calculates the total discount amount for each of the different supported - * discount types. If discounts aren't present or invalid returns 0. - * @param {Cart} cart - the cart to calculate discounts for - * @return {int} the total discounts amount - */ - getDiscountTotal(cart) { - const subtotal = this.getSubtotal(cart, { excludeNonDiscounts: true }) - - if (!cart.discounts || !cart.discounts.length) { - return 0 - } - - // we only support having free shipping and one other discount, so first - // find the discount, which is not free shipping. - const discount = cart.discounts.find( - ({ rule }) => rule.type !== "free_shipping" - ) - - if (!discount) { - return 0 - } - - const { type, allocation, value } = discount.rule - let toReturn = 0 - - if (type === "percentage" && allocation === "total") { - toReturn = (subtotal / 100) * value - } else if (type === "percentage" && allocation === "item") { - const itemPercentageDiscounts = this.getAllocationItemDiscounts( - discount, - cart, - "percentage" - ) - toReturn = _.sumBy(itemPercentageDiscounts, (d) => d.amount) - } else if (type === "fixed" && allocation === "total") { - toReturn = value - } else if (type === "fixed" && allocation === "item") { - const itemFixedDiscounts = this.getAllocationItemDiscounts( - discount, - cart, - "fixed" - ) - toReturn = _.sumBy(itemFixedDiscounts, (d) => d.amount) - } - - if (subtotal < 0) { - return this.rounded(Math.max(subtotal, toReturn)) - } - - return this.rounded(Math.min(subtotal, toReturn)) - } - - rounded(value) { - return Math.round(value) - } -} - -export default TotalsService diff --git a/packages/medusa/src/services/totals.ts b/packages/medusa/src/services/totals.ts new file mode 100644 index 0000000000..b1bf7d2333 --- /dev/null +++ b/packages/medusa/src/services/totals.ts @@ -0,0 +1,957 @@ +import _ from "lodash" +import { BaseService } from "medusa-interfaces" +import { MedusaError } from "medusa-core-utils" + +import { LineItemTaxLine } from "../models/line-item-tax-line" +import { ShippingMethodTaxLine } from "../models/shipping-method-tax-line" +import { Order } from "../models/order" +import { Cart } from "../models/cart" +import { ShippingMethod } from "../models/shipping-method" +import { LineItem } from "../models/line-item" +import { Discount } from "../models/discount" +import { DiscountRuleType } from "../models/discount-rule" + +import TaxProviderService from "./tax-provider" +import { ITaxCalculationStrategy } from "../interfaces/tax-calculation-strategy" +import { TaxCalculationContext } from "../interfaces/tax-service" +import { isCart } from "../types/cart" +import { isOrder } from "../types/orders" + +import { + SubtotalOptions, + LineDiscount, + LineAllocationsMap, + LineDiscountAmount, +} from "../types/totals" + +type ShippingMethodTotals = { + price: number + tax_total: number + total: number + original_total: number + original_tax_total: number + tax_lines: ShippingMethodTaxLine[] +} + +type GetShippingMethodTotalsOptions = { + include_tax?: boolean + use_tax_lines?: boolean +} + +type LineItemTotals = { + unit_price: number + quantity: number + subtotal: number + tax_total: number + total: number + original_total: number + original_tax_total: number + tax_lines: LineItemTaxLine[] + discount_total: number + gift_card_total: number +} + +type LineItemTotalsOptions = { + include_tax?: boolean + use_tax_lines?: boolean +} + +type GetLineItemTotalOptions = { + include_tax?: boolean + exclude_gift_cards?: boolean + exclude_discounts?: boolean +} + +type TotalsServiceProps = { + taxProviderService: TaxProviderService + taxCalculationStrategy: ITaxCalculationStrategy +} + +type GetTotalsOptions = { + force_taxes?: boolean +} + +type AllocationMapOptions = { + exclude_gift_cards?: boolean + exclude_discounts?: boolean +} + +type CalculationContextOptions = { + is_return?: boolean + exclude_shipping?: boolean + exclude_gift_cards?: boolean + exclude_discounts?: boolean +} + +/** + * A service that calculates total and subtotals for orders, carts etc.. + * @implements {BaseService} + */ +class TotalsService extends BaseService { + private taxProviderService_: TaxProviderService + private taxCalculationStrategy_: ITaxCalculationStrategy + + constructor({ + taxProviderService, + taxCalculationStrategy, + }: TotalsServiceProps) { + super() + + this.taxProviderService_ = taxProviderService + this.taxCalculationStrategy_ = taxCalculationStrategy + } + + /** + * Calculates subtotal of a given cart or order. + * @param cartOrOrder - object to calculate total for + * @param options - options to calculate by + * @return the calculated subtotal + */ + async getTotal( + cartOrOrder: Cart | Order, + options: GetTotalsOptions = {} + ): Promise { + const subtotal = this.getSubtotal(cartOrOrder) + const taxTotal = + (await this.getTaxTotal(cartOrOrder, options.force_taxes)) || 0 + const discountTotal = this.getDiscountTotal(cartOrOrder) + const giftCardTotal = this.getGiftCardTotal(cartOrOrder) + const shippingTotal = this.getShippingTotal(cartOrOrder) + + return subtotal + taxTotal + shippingTotal - discountTotal - giftCardTotal + } + + /** + * Gets the total payments made on an order + * @param order - the order to calculate paid amount for + * @return the total paid amount + */ + getPaidTotal(order: Order): number { + const total = order.payments?.reduce((acc, next) => { + acc += next.amount + return acc + }, 0) + + return total + } + + /** + * The total paid for swaps. May be negative in case of negative swap + * difference. + * @param order - the order to calculate swap total for + * @return the swap total + */ + getSwapTotal(order: Order): number { + let swapTotal = 0 + if (order.swaps && order.swaps.length) { + for (const s of order.swaps) { + swapTotal = swapTotal + s.difference_due + } + } + + return swapTotal + } + + /** + * Gets the totals breakdown for a shipping method. Fetches tax lines if not + * already provided. + * @param shippingMethod - the shipping method to get totals breakdown for. + * @param cartOrOrder - the cart or order to use as context for the breakdown + * @param opts - options for what should be included + * @returns An object that breaks down the totals for the shipping method + */ + async getShippingMethodTotals( + shippingMethod: ShippingMethod, + cartOrOrder: Cart | Order, + opts: GetShippingMethodTotalsOptions = {} + ): Promise { + const calculationContext = this.getCalculationContext(cartOrOrder, { + exclude_shipping: true, + }) + calculationContext.shipping_methods = [shippingMethod] + + const totals = { + price: shippingMethod.price, + original_total: shippingMethod.price, + total: shippingMethod.price, + original_tax_total: 0, + tax_total: 0, + tax_lines: shippingMethod.tax_lines || [], + } + + if (opts.include_tax) { + if (isOrder(cartOrOrder) && cartOrOrder.tax_rate !== null) { + totals.original_tax_total = Math.round( + totals.original_tax_total * (cartOrOrder.tax_rate / 100) + ) + totals.tax_total = Math.round( + totals.original_tax_total * (cartOrOrder.tax_rate / 100) + ) + } else { + let taxLines: ShippingMethodTaxLine[] + if (opts.use_tax_lines || isOrder(cartOrOrder)) { + if (typeof shippingMethod.tax_lines === "undefined") { + throw new MedusaError( + MedusaError.Types.UNEXPECTED_STATE, + "Tax Lines must be joined on shipping method to calculate taxes" + ) + } + + taxLines = shippingMethod.tax_lines + } else { + const orderLines = await this.taxProviderService_.getTaxLines( + cartOrOrder.items, + calculationContext + ) + + console.log(orderLines) + + taxLines = orderLines.filter((ol) => { + if ("shipping_method_id" in ol) { + return ol.shipping_method_id === shippingMethod.id + } + return false + }) as ShippingMethodTaxLine[] + } + totals.tax_lines = taxLines + } + + if (totals.tax_lines.length > 0) { + totals.original_tax_total = + await this.taxCalculationStrategy_.calculate( + [], + totals.tax_lines, + calculationContext + ) + totals.tax_total = totals.original_tax_total + + totals.original_total += totals.original_tax_total + totals.total += totals.tax_total + } + } + + if (cartOrOrder.discounts) { + if (cartOrOrder.discounts.some((d) => d.rule.type === "free_shipping")) { + totals.total = 0 + totals.tax_total = 0 + } + } + + return totals + } + + /** + * Calculates subtotal of a given cart or order. + * @param cartOrOrder - cart or order to calculate subtotal for + * @param opts - options + * @return the calculated subtotal + */ + getSubtotal(cartOrOrder: Cart | Order, opts: SubtotalOptions = {}): number { + let subtotal = 0 + if (!cartOrOrder.items) { + return subtotal + } + + cartOrOrder.items.map((item) => { + if (opts.excludeNonDiscounts) { + if (item.allow_discounts) { + subtotal += item.unit_price * item.quantity + } + } else { + subtotal += item.unit_price * item.quantity + } + }) + + return this.rounded(subtotal) + } + + /** + * Calculates shipping total + * @param cartOrOrder - cart or order to calculate subtotal for + * @return shipping total + */ + getShippingTotal(cartOrOrder: Cart | Order): number { + const { shipping_methods } = cartOrOrder + return shipping_methods.reduce((acc, next) => { + return acc + next.price + }, 0) + } + + /** + * Calculates tax total + * Currently based on the Danish tax system + * @param cartOrOrder - cart or order to calculate tax total for + * @param forceTaxes - whether taxes should be calculated regardless + * of region settings + * @return tax total + */ + async getTaxTotal( + cartOrOrder: Cart | Order, + forceTaxes = false + ): Promise { + if ( + isCart(cartOrOrder) && + !forceTaxes && + !cartOrOrder.region.automatic_taxes + ) { + return null + } + + const calculationContext = this.getCalculationContext(cartOrOrder) + + let taxLines: (ShippingMethodTaxLine | LineItemTaxLine)[] + if (isOrder(cartOrOrder)) { + const taxLinesJoined = cartOrOrder.items.every( + (i) => typeof i.tax_lines !== "undefined" + ) + if (!taxLinesJoined) { + throw new MedusaError( + MedusaError.Types.UNEXPECTED_STATE, + "Order tax calculations must have tax lines joined on line items" + ) + } + + if (cartOrOrder.tax_rate === null) { + taxLines = cartOrOrder.items.flatMap((li) => li.tax_lines) + + const shippingTaxLines = cartOrOrder.shipping_methods.flatMap( + (sm) => sm.tax_lines + ) + + taxLines = taxLines.concat(shippingTaxLines) + } else { + const subtotal = this.getSubtotal(cartOrOrder) + const shippingTotal = this.getShippingTotal(cartOrOrder) + const discountTotal = this.getDiscountTotal(cartOrOrder) + const giftCardTotal = this.getGiftCardTotal(cartOrOrder) + return this.rounded( + (subtotal - discountTotal - giftCardTotal + shippingTotal) * + (cartOrOrder.tax_rate / 100) + ) + } + } else { + taxLines = await this.taxProviderService_.getTaxLines( + cartOrOrder.items, + calculationContext + ) + + if (cartOrOrder.type === "swap") { + const returnTaxLines = cartOrOrder.items.flatMap((i) => { + if (i.is_return) { + if (typeof i.tax_lines === "undefined") { + throw new MedusaError( + MedusaError.Types.UNEXPECTED_STATE, + "Return Line Items must join tax lines" + ) + } + return i.tax_lines + } + + return [] + }) + + taxLines = taxLines.concat(returnTaxLines) + } + } + + const toReturn = await this.taxCalculationStrategy_.calculate( + cartOrOrder.items, + taxLines, + calculationContext + ) + + return this.rounded(toReturn) + } + + /** + * Gets a map of discounts and gift cards that apply to line items in an + * order. The function calculates the amount of a discount or gift card that + * applies to a specific line item. + * @param orderOrCart - the order or cart to get an allocation map for + * @param options - controls what should be included in allocation map + * @return the allocation map for the line items in the cart or order. + */ + getAllocationMap( + orderOrCart: Cart | Order, + options: AllocationMapOptions = {} + ): LineAllocationsMap { + const allocationMap: LineAllocationsMap = {} + + if (!options.exclude_discounts) { + let lineDiscounts: LineDiscountAmount[] = [] + + const discount = orderOrCart.discounts.find( + ({ rule }) => rule.type !== "free_shipping" + ) + if (discount) { + lineDiscounts = this.getLineDiscounts(orderOrCart, discount) + } + + for (const ld of lineDiscounts) { + if (allocationMap[ld.item.id]) { + allocationMap[ld.item.id].discount = { + amount: ld.amount, + unit_amount: ld.amount / ld.item.quantity, + } + } else { + allocationMap[ld.item.id] = { + discount: { + amount: ld.amount, + unit_amount: ld.amount / ld.item.quantity, + }, + } + } + } + } + + if (!options.exclude_gift_cards) { + let lineGiftCards: LineDiscountAmount[] = [] + if (orderOrCart.gift_cards && orderOrCart.gift_cards.length) { + const subtotal = this.getSubtotal(orderOrCart) + const giftCardTotal = this.getGiftCardTotal(orderOrCart) + + // If the fixed discount exceeds the subtotal we should + // calculate a 100% discount + const nominator = Math.min(giftCardTotal, subtotal) + const percentage = nominator / subtotal + + lineGiftCards = orderOrCart.items.map((l) => { + return { + item: l, + amount: l.unit_price * l.quantity * percentage, + } + }) + } + + for (const lgc of lineGiftCards) { + if (allocationMap[lgc.item.id]) { + allocationMap[lgc.item.id].gift_card = { + amount: lgc.amount, + unit_amount: lgc.amount / lgc.item.quantity, + } + } else { + allocationMap[lgc.item.id] = { + discount: { + amount: lgc.amount, + unit_amount: lgc.amount / lgc.item.quantity, + }, + } + } + } + } + + return allocationMap + } + + /** + * Gets the total refund amount for an order. + * @param order - the order to get total refund amount for. + * @return the total refunded amount for an order. + */ + getRefundedTotal(order: Order): number { + if (!order.refunds) { + return 0 + } + + const total = order.refunds.reduce((acc, next) => acc + next.amount, 0) + return this.rounded(total) + } + + /** + * The amount that can be refunded for a given line item. + * @param order - order to use as context for the calculation + * @param lineItem - the line item to calculate the refund amount for. + * @return the line item refund amount. + */ + getLineItemRefund(order: Order, lineItem: LineItem): number { + const allocationMap = this.getAllocationMap(order) + + const discountAmount = + (allocationMap[lineItem.id]?.discount?.unit_amount || 0) * + lineItem.quantity + const lineSubtotal = + lineItem.unit_price * lineItem.quantity - discountAmount + + /* + * Used for backcompat with old tax system + */ + if (order.tax_rate !== null) { + const taxRate = order.tax_rate / 100 + return this.rounded(lineSubtotal * (1 + taxRate)) + } + + /* + * New tax system uses the tax lines registerd on the line items + */ + if (typeof lineItem.tax_lines === "undefined") { + throw new MedusaError( + MedusaError.Types.UNEXPECTED_STATE, + "Tax calculation did not receive tax_lines" + ) + } + + const taxTotal = lineItem.tax_lines.reduce((acc, next) => { + const taxRate = next.rate / 100 + return acc + this.rounded(lineSubtotal * taxRate) + }, 0) + + return lineSubtotal + taxTotal + } + + /** + * Calculates refund total of line items. + * If any of the items to return have been discounted, we need to + * apply the discount again before refunding them. + * @param order - cart or order to calculate subtotal for + * @param lineItems - the line items to calculate refund total for + * @return the calculated subtotal + */ + getRefundTotal(order: Order, lineItems: LineItem[]): number { + let itemIds = order.items.map((i) => i.id) + + // in case we swap a swap, we need to include swap items + if (order.swaps && order.swaps.length) { + for (const s of order.swaps) { + const swapItemIds = s.additional_items.map((el) => el.id) + itemIds = [...itemIds, ...swapItemIds] + } + } + + if (order.claims && order.claims.length) { + for (const c of order.claims) { + const claimItemIds = c.additional_items.map((el) => el.id) + itemIds = [...itemIds, ...claimItemIds] + } + } + + const refunds = lineItems.map((i) => { + if (!itemIds.includes(i.id)) { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + "Line item does not exist on order" + ) + } + + return this.getLineItemRefund(order, i) + }) + + return this.rounded(refunds.reduce((acc, next) => acc + next, 0)) + } + + /** + * Calculates either fixed or percentage discount of a variant + * @param lineItem - id of line item + * @param variant - id of variant in line item + * @param variantPrice - price of the variant based on region + * @param value - discount value + * @param discountType - the type of discount (fixed or percentage) + * @return triples of lineitem, variant and applied discount + */ + calculateDiscount_( + lineItem: LineItem, + variant: string, + variantPrice: number, + value: number, + discountType: DiscountRuleType + ): LineDiscount { + if (!lineItem.allow_discounts) { + return { + lineItem, + variant, + amount: 0, + } + } + if (discountType === DiscountRuleType.PERCENTAGE) { + return { + lineItem, + variant, + amount: ((variantPrice * lineItem.quantity) / 100) * value, + } + } else { + return { + lineItem, + variant, + amount: + value >= variantPrice * lineItem.quantity + ? variantPrice * lineItem.quantity + : value * lineItem.quantity, + } + } + } + + /** + * If the rule of a discount has allocation="item", then we need + * to calculate discount on each item in the cart. Furthermore, we need to + * make sure to only apply the discount on valid variants. And finally we + * return ether an array of percentages discounts or fixed discounts + * alongside the variant on which the discount was applied. + * @param discount - the discount to which we do the calculation + * @param cart - the cart to calculate discounts for + * @return array of triples of lineitem, variant and applied discount + */ + getAllocationItemDiscounts( + discount: Discount, + cart: Cart | Order + ): LineDiscount[] { + const discounts: LineDiscount[] = [] + for (const item of cart.items) { + if (discount.rule.valid_for?.length > 0) { + discount.rule.valid_for.map(({ id }) => { + if (item.variant.product_id === id) { + discounts.push( + this.calculateDiscount_( + item, + item.variant.id, + item.unit_price, + discount.rule.value, + discount.rule.type + ) + ) + } + }) + } + } + return discounts + } + + /** + * Returns the discount amount allocated to the line items of an order. + * @param cartOrOrder - the cart or order to get line discount allocations for + * @param discount - the discount to use as context for the calculation + * @return the allocations that the discount has on the items in the cart or + * order + */ + getLineDiscounts( + cartOrOrder: Cart | Order, + discount: Discount + ): LineDiscountAmount[] { + const subtotal = this.getSubtotal(cartOrOrder, { + excludeNonDiscounts: true, + }) + + let merged: LineItem[] = [...cartOrOrder.items] + + // merge items from order with items from order swaps + if ("swaps" in cartOrOrder && cartOrOrder.swaps.length) { + for (const s of cartOrOrder.swaps) { + merged = [...merged, ...s.additional_items] + } + } + + if ("claims" in cartOrOrder && cartOrOrder.claims.length) { + for (const c of cartOrOrder.claims) { + merged = [...merged, ...c.additional_items] + } + } + + const { type, allocation, value } = discount.rule + if (allocation === "total") { + let percentage = 0 + if (type === "percentage") { + percentage = value / 100 + } else if (type === "fixed") { + // If the fixed discount exceeds the subtotal we should + // calculate a 100% discount + const nominator = Math.min(value, subtotal) + percentage = nominator / subtotal + } + + return merged.map((item) => { + const lineTotal = item.unit_price * item.quantity + + return { + item, + amount: item.allow_discounts ? lineTotal * percentage : 0, + } + }) + } else if (allocation === "item") { + const allocationDiscounts = this.getAllocationItemDiscounts( + discount, + cartOrOrder + ) + return merged.map((item) => { + const discounted = allocationDiscounts.find( + (a) => a.lineItem.id === item.id + ) + return { + item, + amount: discounted ? discounted.amount : 0, + } + }) + } + + return merged.map((i) => ({ item: i, amount: 0 })) + } + + /** + * Breaks down the totals related to a line item; these are the subtotal, the + * amount of discount applied to the line item, the amount of a gift card + * applied to a line item and the amount of tax applied to a line item. + * @param lineItem - the line item to calculate totals for + * @param cartOrOrder - the cart or order to use as context for the calculation + * @param options - the options to evaluate the line item totals for + * @returns the breakdown of the line item totals + */ + async getLineItemTotals( + lineItem: LineItem, + cartOrOrder: Cart | Order, + options: LineItemTotalsOptions = {} + ): Promise { + const calculationContext = this.getCalculationContext(cartOrOrder, { + exclude_shipping: true, + }) + + const lineItemAllocation = + calculationContext.allocation_map[lineItem.id] || {} + + const subtotal = lineItem.unit_price * lineItem.quantity + const gift_card_total = lineItemAllocation.gift_card?.amount || 0 + const discount_total = + (lineItemAllocation.discount?.unit_amount || 0) * lineItem.quantity + + const lineItemTotals: LineItemTotals = { + unit_price: lineItem.unit_price, + quantity: lineItem.quantity, + subtotal, + gift_card_total, + discount_total, + total: subtotal - discount_total, + original_total: subtotal, + original_tax_total: 0, + tax_total: 0, + tax_lines: lineItem.tax_lines || [], + } + + // Tax Information + if (options.include_tax) { + // When we have an order with a null'ed tax rate we know that it is an + // order from the old tax system. The following is a backward compat + // calculation. + if (isOrder(cartOrOrder) && cartOrOrder.tax_rate !== null) { + lineItemTotals.original_tax_total = + subtotal * (cartOrOrder.tax_rate / 100) + lineItemTotals.tax_total = + (subtotal - discount_total) * (cartOrOrder.tax_rate / 100) + + lineItemTotals.total += lineItemTotals.tax_total + lineItemTotals.original_total += lineItemTotals.original_tax_total + } else { + let taxLines: LineItemTaxLine[] + + /* + * Line Items on orders will already have tax lines. But for cart line + * items we have to get the line items from the tax provider. + */ + if (options.use_tax_lines || isOrder(cartOrOrder)) { + if (typeof lineItem.tax_lines === "undefined") { + throw new MedusaError( + MedusaError.Types.UNEXPECTED_STATE, + "Tax Lines must be joined on items to calculate taxes" + ) + } + + taxLines = lineItem.tax_lines + } else { + if (lineItem.is_return) { + if (typeof lineItem.tax_lines === "undefined") { + throw new MedusaError( + MedusaError.Types.UNEXPECTED_STATE, + "Return Line Items must join tax lines" + ) + } + taxLines = lineItem.tax_lines + } else { + const orderLines = await this.taxProviderService_.getTaxLines( + cartOrOrder.items, + calculationContext + ) + + taxLines = orderLines.filter((ol) => { + if ("item_id" in ol) { + return ol.item_id === lineItem.id + } + return false + }) as LineItemTaxLine[] + } + } + + lineItemTotals.tax_lines = taxLines + } + } + + if (lineItemTotals.tax_lines.length > 0) { + lineItemTotals.tax_total = await this.taxCalculationStrategy_.calculate( + [lineItem], + lineItemTotals.tax_lines, + calculationContext + ) + lineItemTotals.total += lineItemTotals.tax_total + + calculationContext.allocation_map = {} // Don't account for discounts + lineItemTotals.original_tax_total = + await this.taxCalculationStrategy_.calculate( + [lineItem], + lineItemTotals.tax_lines, + calculationContext + ) + lineItemTotals.original_total += lineItemTotals.original_tax_total + } + + return lineItemTotals + } + + /** + * Gets a total for a line item. The total can take gift cards, discounts and + * taxes into account. This can be controlled through the options. + * @param lineItem - the line item to calculate a total for + * @param cartOrOrder - the cart or order to use as context for the calculation + * @param options - the options to use for the calculation + * @returns the line item total + */ + async getLineItemTotal( + lineItem: LineItem, + cartOrOrder: Cart | Order, + options: GetLineItemTotalOptions = {} + ): Promise { + const lineItemTotals = await this.getLineItemTotals(lineItem, cartOrOrder, { + include_tax: options.include_tax, + }) + + let toReturn = lineItemTotals.subtotal + if (!options.exclude_discounts) { + toReturn += lineItemTotals.discount_total + } + + if (!options.exclude_gift_cards) { + toReturn += lineItemTotals.gift_card_total + } + + if (options.include_tax) { + toReturn += lineItemTotals.tax_total + } + + return toReturn + } + + /** + * Gets the gift card amount on a cart or order. + * @param cartOrOrder - the cart or order to get gift card amount for + * @return the gift card amount applied to the cart or order + */ + getGiftCardTotal(cartOrOrder: Cart | Order): number { + const giftCardable = + this.getSubtotal(cartOrOrder) - this.getDiscountTotal(cartOrOrder) + + if ("gift_card_transactions" in cartOrOrder) { + return cartOrOrder.gift_card_transactions.reduce( + (acc, next) => acc + next.amount, + 0 + ) + } + + if (!cartOrOrder.gift_cards || !cartOrOrder.gift_cards.length) { + return 0 + } + + const toReturn = cartOrOrder.gift_cards.reduce( + (acc, next) => acc + next.balance, + 0 + ) + return Math.min(giftCardable, toReturn) + } + + /** + * Calculates the total discount amount for each of the different supported + * discount types. If discounts aren't present or invalid returns 0. + * @param cartOrOrder - the cart or order to calculate discounts for + * @return the total discounts amount + */ + getDiscountTotal(cartOrOrder: Cart | Order): number { + const subtotal = this.getSubtotal(cartOrOrder, { + excludeNonDiscounts: true, + }) + + if (!cartOrOrder.discounts || !cartOrOrder.discounts.length) { + return 0 + } + + // we only support having free shipping and one other discount, so first + // find the discount, which is not free shipping. + const discount = cartOrOrder.discounts.find( + ({ rule }) => rule.type !== "free_shipping" + ) + + if (!discount) { + return 0 + } + + const { type, allocation, value } = discount.rule + let toReturn = 0 + + if (type === "percentage" && allocation === "total") { + toReturn = (subtotal / 100) * value + } else if (type === "percentage" && allocation === "item") { + const itemPercentageDiscounts = this.getAllocationItemDiscounts( + discount, + cartOrOrder + ) + toReturn = _.sumBy(itemPercentageDiscounts, (d) => d.amount) + } else if (type === "fixed" && allocation === "total") { + toReturn = value + } else if (type === "fixed" && allocation === "item") { + const itemFixedDiscounts = this.getAllocationItemDiscounts( + discount, + cartOrOrder + ) + toReturn = _.sumBy(itemFixedDiscounts, (d) => d.amount) + } + + if (subtotal < 0) { + return this.rounded(Math.max(subtotal, toReturn)) + } + + return this.rounded(Math.min(subtotal, toReturn)) + } + + /** + * Prepares the calculation context for a tax total calculation. + * @param cartOrOrder - the cart or order to get the calculation context for + * @param options - options to gather context by + * @return the tax calculation context + */ + getCalculationContext( + cartOrOrder: Cart | Order, + options: CalculationContextOptions = {} + ): TaxCalculationContext { + const allocationMap = this.getAllocationMap(cartOrOrder, { + exclude_gift_cards: options.exclude_gift_cards, + exclude_discounts: options.exclude_discounts, + }) + + let shippingMethods: ShippingMethod[] = [] + // Default to include shipping methods + if (!options.exclude_shipping) { + shippingMethods = cartOrOrder.shipping_methods || [] + } + + return { + shipping_address: cartOrOrder.shipping_address, + shipping_methods: shippingMethods, + customer: cartOrOrder.customer, + region: cartOrOrder.region, + is_return: options.is_return ?? false, + allocation_map: allocationMap, + } + } + + /** + * Rounds a number using Math.round. + * @param value - the value to round + * @return the rounded value + */ + rounded(value: number): number { + return Math.round(value) + } +} + +export default TotalsService diff --git a/packages/medusa/src/strategies/__mocks__/cart-completion.js b/packages/medusa/src/strategies/__mocks__/cart-completion.js new file mode 100644 index 0000000000..a79c4a5be9 --- /dev/null +++ b/packages/medusa/src/strategies/__mocks__/cart-completion.js @@ -0,0 +1,14 @@ +export const CompletionStrategyMock = { + complete: jest.fn(() => + Promise.resolve({ + response_code: 200, + response_body: {}, + }) + ), +} + +const mock = jest.fn().mockImplementation(() => { + return CompletionStrategyMock +}) + +export default mock diff --git a/packages/medusa/src/strategies/__tests__/cart-completion.js b/packages/medusa/src/strategies/__tests__/cart-completion.js new file mode 100644 index 0000000000..328ac2b1e9 --- /dev/null +++ b/packages/medusa/src/strategies/__tests__/cart-completion.js @@ -0,0 +1,221 @@ +import { MockManager } from "medusa-test-utils" +import CartCompletionStrategy from "../cart-completion" + +const IdempotencyKeyServiceMock = { + withTransaction: function () { + return this + }, + workStage: jest.fn().mockImplementation(async (key, fn) => { + try { + const { recovery_point, response_code, response_body } = await fn( + MockManager + ) + + if (recovery_point) { + return { + key: { idempotency_key: key, recovery_point }, + } + } else { + return { + key: { + recovery_point: "finished", + response_body, + response_code, + }, + } + } + } catch (err) { + return { error: err } + } + }), +} + +const toTest = [ + [ + "succeeds", + { + cart: { + id: "test-cart", + items: [], + payment: { data: "some-data" }, + payment_session: { status: "authorized" }, + total: 1000, + region_id: "testRegion", + }, + idempotencyKey: { + id: "ikey", + idempotency_key: "ikey", + recovery_point: "started", + }, + validate: function (value, { cartServiceMock, orderServiceMock }) { + expect(value.response_code).toEqual(200) + expect(value.response_body).toEqual({ + data: expect.any(Object), + type: "order", + }) + + expect(cartServiceMock.createTaxLines).toHaveBeenCalledTimes(1) + expect(cartServiceMock.createTaxLines).toHaveBeenCalledWith("test-cart") + + expect(cartServiceMock.authorizePayment).toHaveBeenCalledTimes(1) + expect(cartServiceMock.authorizePayment).toHaveBeenCalledWith( + "test-cart", + { + idempotency_key: "ikey", + } + ) + + expect(orderServiceMock.createFromCart).toHaveBeenCalledTimes(1) + expect(orderServiceMock.createFromCart).toHaveBeenCalledWith( + "test-cart" + ) + + expect(orderServiceMock.retrieve).toHaveBeenCalledTimes(1) + expect(orderServiceMock.retrieve).toHaveBeenCalledWith("test-cart", { + select: [ + "subtotal", + "tax_total", + "shipping_total", + "discount_total", + "total", + ], + relations: ["shipping_address", "items", "payments"], + }) + }, + }, + ], + [ + "returns 409", + { + cart: { + id: "test-cart", + items: [], + completed_at: "2021-01-02", + payment: { data: "some-data" }, + payment_session: { status: "authorized" }, + total: 1000, + region_id: "testRegion", + }, + idempotencyKey: { + id: "ikey", + idempotency_key: "ikey", + recovery_point: "started", + }, + validate: function (value) { + expect(value.response_code).toEqual(409) + expect(value.response_body).toEqual({ + code: "cart_incompatible_state", + message: "Cart has already been completed", + type: "not_allowed", + }) + }, + }, + ], + [ + "returns requires more", + { + cart: { + id: "test-cart", + items: [], + payment: { data: "some-data" }, + payment_session: { status: "requires_more" }, + total: 1000, + region_id: "testRegion", + }, + idempotencyKey: { + id: "ikey", + idempotency_key: "ikey", + recovery_point: "started", + }, + validate: function (value) { + expect(value.response_code).toEqual(200) + expect(value.response_body).toEqual({ + data: expect.any(Object), + payment_status: "requires_more", + type: "cart", + }) + }, + }, + ], + [ + "creates swap", + { + cart: { + id: "test-cart", + type: "swap", + items: [], + payment: { data: "some-data" }, + payment_session: { status: "authorized" }, + total: 1000, + region_id: "testRegion", + metadata: { swap_id: "testswap" }, + }, + idempotencyKey: { + id: "ikey", + idempotency_key: "ikey", + recovery_point: "started", + }, + validate: function (value, { swapServiceMock }) { + expect(value.response_code).toEqual(200) + expect(value.response_body).toEqual({ + data: expect.any(Object), + type: "swap", + }) + + expect(swapServiceMock.registerCartCompletion).toHaveBeenCalledTimes(1) + expect(swapServiceMock.registerCartCompletion).toHaveBeenCalledWith( + "testswap" + ) + }, + }, + ], +] + +describe("CartCompletionStrategy", () => { + describe("complete", () => { + test.each(toTest)( + "%s", + async (title, { cart, idempotencyKey, validate }) => { + const cartServiceMock = { + withTransaction: function () { + return this + }, + createTaxLines: jest.fn(() => Promise.resolve(cart)), + authorizePayment: jest.fn(() => Promise.resolve(cart)), + retrieve: jest.fn(() => Promise.resolve(cart)), + } + const orderServiceMock = { + withTransaction: function () { + return this + }, + createFromCart: jest.fn(() => Promise.resolve(cart)), + retrieve: jest.fn(() => Promise.resolve({})), + } + const swapServiceMock = { + withTransaction: function () { + return this + }, + registerCartCompletion: jest.fn(() => Promise.resolve({})), + retrieve: jest.fn(() => Promise.resolve({})), + } + const idempotencyKeyServiceMock = IdempotencyKeyServiceMock + + const completionStrat = new CartCompletionStrategy({ + cartService: cartServiceMock, + idempotencyKeyService: idempotencyKeyServiceMock, + orderService: orderServiceMock, + swapService: swapServiceMock, + }) + + const val = await completionStrat.complete(cart.id, idempotencyKey, {}) + + validate(val, { + cartServiceMock, + orderServiceMock, + swapServiceMock, + idempotencyKeyServiceMock, + }) + } + ) + }) +}) diff --git a/packages/medusa/src/strategies/__tests__/tax-calculation.js b/packages/medusa/src/strategies/__tests__/tax-calculation.js new file mode 100644 index 0000000000..efe741355b --- /dev/null +++ b/packages/medusa/src/strategies/__tests__/tax-calculation.js @@ -0,0 +1,124 @@ +import TaxCalculationStrategy from "../tax-calculation" + +const toTest = [ + { + title: "calculates correctly without gift card", + + /* + * Subtotal = 2 * 100 = 200 + * Taxable amount = 200 - 10 = 190 + * Taxline 1 = 190 * 0.0825 = 15.675 = 16 + * Taxline 2 = 190 * 0.125 = 13.75 = 14 + * Total tax = 40 + */ + expected: 40, + items: [ + { + id: "item_1", + unit_price: 100, + quantity: 2, + }, + ], + taxLines: [ + { + item_id: "item_1", + name: "Name 1", + rate: 8.25, + }, + { + item_id: "item_1", + name: "Name 2", + rate: 12.5, + }, + ], + context: { + shipping_address: null, + customer: { + email: "test@testson.com", + }, + shipping_methods: [], + region: { + gift_cards_taxable: false, + }, + allocation_map: { + item_1: { + discount: { + amount: 10, + unit_amount: 5, + }, + gift_card: { + amount: 10, + unit_amount: 5, + }, + }, + }, + }, + }, + { + title: "calculates correctly with gift card", + + /* + * Subtotal = 2 * 100 = 200 + * Taxable amount = 200 - 10 = 180 + * Taxline 1 = 180 * 0.0825 = 15 + * Taxline 2 = 180 * 0.125 = 23 + * Total tax = 38 + */ + expected: 38, + items: [ + { + id: "item_1", + unit_price: 100, + quantity: 2, + }, + ], + taxLines: [ + { + item_id: "item_1", + name: "Name 1", + rate: 8.25, + }, + { + item_id: "item_1", + name: "Name 2", + rate: 12.5, + }, + ], + context: { + shipping_address: null, + customer: { + email: "test@testson.com", + }, + region: { + gift_cards_taxable: true, + }, + shipping_methods: [], + allocation_map: { + item_1: { + discount: { + amount: 10, + unit_amount: 5, + }, + gift_card: { + amount: 10, + unit_amount: 5, + }, + }, + }, + }, + }, +] + +describe("TaxCalculationStrategy", () => { + describe("calculate", () => { + const calcStrat = new TaxCalculationStrategy() + + test.each(toTest)( + "$title", + async ({ items, taxLines, context, expected }) => { + const val = await calcStrat.calculate(items, taxLines, context) + expect(val).toEqual(expected) + } + ) + }) +}) diff --git a/packages/medusa/src/strategies/cart-completion.ts b/packages/medusa/src/strategies/cart-completion.ts new file mode 100644 index 0000000000..89c01d4e7b --- /dev/null +++ b/packages/medusa/src/strategies/cart-completion.ts @@ -0,0 +1,294 @@ +import { EntityManager } from "typeorm" +import { MedusaError } from "medusa-core-utils" + +import { IdempotencyKey } from "../models/idempotency-key" +import { Order } from "../models/order" +import CartService from "../services/cart" +import { RequestContext } from "../types/request" +import OrderService from "../services/order" +import IdempotencyKeyService from "../services/idempotency-key" +import SwapService from "../services/swap" + +import { ICartCompletionStrategy, CartCompletionResponse } from "../interfaces" + +class CartCompletionStrategy implements ICartCompletionStrategy { + private idempotencyKeyService_: IdempotencyKeyService + private cartService_: CartService + private orderService_: OrderService + private swapService_: SwapService + + constructor({ + idempotencyKeyService, + cartService, + orderService, + swapService, + }) { + this.idempotencyKeyService_ = idempotencyKeyService + this.cartService_ = cartService + this.orderService_ = orderService + this.swapService_ = swapService + } + + async complete( + id: string, + ikey: IdempotencyKey, + context: RequestContext + ): Promise { + let idempotencyKey: IdempotencyKey = ikey + + const idempotencyKeyService = this.idempotencyKeyService_ + const cartService = this.cartService_ + const orderService = this.orderService_ + const swapService = this.swapService_ + + let inProgress = true + let err = false + + while (inProgress) { + switch (idempotencyKey.recovery_point) { + case "started": { + const { key, error } = await idempotencyKeyService.workStage( + idempotencyKey.idempotency_key, + async (manager: EntityManager) => { + const cart = await cartService + .withTransaction(manager) + .retrieve(id) + + if (cart.completed_at) { + return { + response_code: 409, + response_body: { + code: MedusaError.Codes.CART_INCOMPATIBLE_STATE, + message: "Cart has already been completed", + type: MedusaError.Types.NOT_ALLOWED, + }, + } + } + + await cartService.withTransaction(manager).createTaxLines(id) + + return { + recovery_point: "tax_lines_created", + } + } + ) + + if (error) { + inProgress = false + err = error + } else { + idempotencyKey = key + } + break + } + case "tax_lines_created": { + const { key, error } = await idempotencyKeyService.workStage( + idempotencyKey.idempotency_key, + async (manager: EntityManager) => { + const cart = await cartService + .withTransaction(manager) + .authorizePayment(id, { + ...context, + idempotency_key: idempotencyKey.idempotency_key, + }) + + if (cart.payment_session) { + if ( + cart.payment_session.status === "requires_more" || + cart.payment_session.status === "pending" + ) { + return { + response_code: 200, + response_body: { + data: cart, + payment_status: cart.payment_session.status, + type: "cart", + }, + } + } + } + + return { + recovery_point: "payment_authorized", + } + } + ) + + if (error) { + inProgress = false + err = error + } else { + idempotencyKey = key + } + break + } + + case "payment_authorized": { + const { key, error } = await idempotencyKeyService.workStage( + idempotencyKey.idempotency_key, + async (manager: EntityManager) => { + const cart = await cartService + .withTransaction(manager) + .retrieve(id, { + select: ["total"], + relations: ["payment", "payment_sessions"], + }) + + // If cart is part of swap, we register swap as complete + switch (cart.type) { + case "swap": { + try { + const swapId = cart.metadata?.swap_id + let swap = await swapService + .withTransaction(manager) + .registerCartCompletion(swapId) + + swap = await swapService + .withTransaction(manager) + .retrieve(swap.id, { relations: ["shipping_address"] }) + + return { + response_code: 200, + response_body: { data: swap, type: "swap" }, + } + } catch (error) { + if ( + error && + error.code === MedusaError.Codes.INSUFFICIENT_INVENTORY + ) { + return { + response_code: 409, + response_body: { + message: error.message, + type: error.type, + code: error.code, + }, + } + } else { + throw error + } + } + } + // case "payment_link": + default: { + if (typeof cart.total === "undefined") { + return { + response_code: 500, + response_body: { + message: "Unexpected state", + }, + } + } + + if (!cart.payment && cart.total > 0) { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + `Cart payment not authorized` + ) + } + + let order: Order + try { + order = await orderService + .withTransaction(manager) + .createFromCart(cart.id) + } catch (error) { + if ( + error && + error.message === "Order from cart already exists" + ) { + order = await orderService + .withTransaction(manager) + .retrieveByCartId(id, { + select: [ + "subtotal", + "tax_total", + "shipping_total", + "discount_total", + "total", + ], + relations: ["shipping_address", "items", "payments"], + }) + + return { + response_code: 200, + response_body: { data: order, type: "order" }, + } + } else if ( + error && + error.code === MedusaError.Codes.INSUFFICIENT_INVENTORY + ) { + return { + response_code: 409, + response_body: { + message: error.message, + type: error.type, + code: error.code, + }, + } + } else { + throw error + } + } + + order = await orderService + .withTransaction(manager) + .retrieve(order.id, { + select: [ + "subtotal", + "tax_total", + "shipping_total", + "discount_total", + "total", + ], + relations: ["shipping_address", "items", "payments"], + }) + + return { + response_code: 200, + response_body: { data: order, type: "order" }, + } + } + } + } + ) + + if (error) { + inProgress = false + err = error + } else { + idempotencyKey = key + } + break + } + + case "finished": { + inProgress = false + break + } + + default: + idempotencyKey = await idempotencyKeyService.update( + idempotencyKey.idempotency_key, + { + recovery_point: "finished", + response_code: 500, + response_body: { message: "Unknown recovery point" }, + } + ) + break + } + } + + if (err) { + throw err + } + + return { + response_body: idempotencyKey.response_body, + response_code: idempotencyKey.response_code, + } + } +} + +export default CartCompletionStrategy diff --git a/packages/medusa/src/strategies/tax-calculation.ts b/packages/medusa/src/strategies/tax-calculation.ts new file mode 100644 index 0000000000..564ad9d742 --- /dev/null +++ b/packages/medusa/src/strategies/tax-calculation.ts @@ -0,0 +1,74 @@ +import { LineItem } from "../models/line-item" +import { ShippingMethod } from "../models/shipping-method" +import { LineItemTaxLine } from "../models/line-item-tax-line" +import { ShippingMethodTaxLine } from "../models/shipping-method-tax-line" +import { TaxCalculationContext } from "../interfaces/tax-service" +import { ITaxCalculationStrategy } from "../interfaces/tax-calculation-strategy" + +class TaxCalculationStrategy implements ITaxCalculationStrategy { + async calculate( + items: LineItem[], + taxLines: (ShippingMethodTaxLine | LineItemTaxLine)[], + calculationContext: TaxCalculationContext + ): Promise { + const lineItemsTaxLines = taxLines.filter( + (tl) => "item_id" in tl + ) as LineItemTaxLine[] + const shippingMethodsTaxLines = taxLines.filter( + (tl) => "shipping_method_id" in tl + ) as ShippingMethodTaxLine[] + + return Math.round( + this.calculateLineItemsTax(items, lineItemsTaxLines, calculationContext) + + this.calculateShippingMethodsTax( + calculationContext.shipping_methods, + shippingMethodsTaxLines + ) + ) + } + + private calculateLineItemsTax( + items: LineItem[], + taxLines: LineItemTaxLine[], + context: TaxCalculationContext + ): number { + let taxTotal = 0 + for (const i of items) { + const allocations = context.allocation_map[i.id] || {} + + let taxableAmount = i.quantity * i.unit_price + + if (context.region.gift_cards_taxable) { + taxableAmount -= + (allocations.gift_card && allocations.gift_card.amount) || 0 + } + + taxableAmount -= + ((allocations.discount && allocations.discount.unit_amount) || 0) * + i.quantity + + const lineRates = taxLines.filter((tl) => tl.item_id === i.id) + for (const lineRate of lineRates) { + taxTotal += Math.round(taxableAmount * (lineRate.rate / 100)) + } + } + return taxTotal + } + + private calculateShippingMethodsTax( + shipping_methods: ShippingMethod[], + taxLines: ShippingMethodTaxLine[] + ): number { + let taxTotal = 0 + for (const sm of shipping_methods) { + const amount = sm.price + const lineRates = taxLines.filter((tl) => tl.shipping_method_id === sm.id) + for (const lineRate of lineRates) { + taxTotal += Math.round(amount * (lineRate.rate / 100)) + } + } + return taxTotal + } +} + +export default TaxCalculationStrategy diff --git a/packages/medusa/src/types/cart.ts b/packages/medusa/src/types/cart.ts index 8486e34d58..249c0c9af0 100644 --- a/packages/medusa/src/types/cart.ts +++ b/packages/medusa/src/types/cart.ts @@ -1,12 +1,17 @@ import { ValidateNested } from "class-validator" import { IsType } from "../utils/validators/is-type" -import { CartType } from "../models/cart" +import { Cart, CartType } from "../models/cart" import { AddressPayload, DateComparisonOperator, StringComparisonOperator, } from "./common" +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function isCart(object: any): object is Cart { + return object.object === "cart" +} + export class FilterableCartProps { @ValidateNested() @IsType([String, [String], StringComparisonOperator]) diff --git a/packages/medusa/src/types/common.ts b/packages/medusa/src/types/common.ts index f2f6d41b70..40be2a99f5 100644 --- a/packages/medusa/src/types/common.ts +++ b/packages/medusa/src/types/common.ts @@ -22,7 +22,7 @@ export interface FindConfig { skip?: number take?: number relations?: string[] - order?: { [k: string]: "ASC" | "DESC" } + order?: { [k: symbol]: "ASC" | "DESC" } } export type PaginatedResponse = { limit: number; offset: number; count: number } diff --git a/packages/medusa/src/types/orders.ts b/packages/medusa/src/types/orders.ts index 3bb0f5a235..1ac4cb014c 100644 --- a/packages/medusa/src/types/orders.ts +++ b/packages/medusa/src/types/orders.ts @@ -8,8 +8,14 @@ import { IsString, ValidateNested, } from "class-validator" +import { Order } from "../models/order" import { DateComparisonOperator } from "./common" +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function isOrder(object: any): object is Order { + return object.object === "order" +} + enum OrderStatus { pending = "pending", completed = "completed", diff --git a/packages/medusa/src/types/product-tax-rate.ts b/packages/medusa/src/types/product-tax-rate.ts new file mode 100644 index 0000000000..a71c649b5b --- /dev/null +++ b/packages/medusa/src/types/product-tax-rate.ts @@ -0,0 +1,11 @@ +import { DateComparisonOperator } from "./common" + +/** + * The filters that can be applied when querying for shipping tax rates. + */ +export class FilterableProductTaxRateProps { + product_id?: string | string[] + rate_id?: string | string[] + created_at?: DateComparisonOperator + updated_at?: DateComparisonOperator +} diff --git a/packages/medusa/src/types/product.ts b/packages/medusa/src/types/product.ts index c0175d1684..c8198ce33a 100644 --- a/packages/medusa/src/types/product.ts +++ b/packages/medusa/src/types/product.ts @@ -24,3 +24,19 @@ export class FilterableProductTagProps { @IsType([DateComparisonOperator]) updated_at?: DateComparisonOperator } + +export class FilterableProductTypeProps { + @ValidateNested() + @IsType([String, [String], StringComparisonOperator]) + id?: string | string[] | StringComparisonOperator + + @ValidateNested() + @IsType([String, [String], StringComparisonOperator]) + value?: string | string[] | StringComparisonOperator + + @IsType([DateComparisonOperator]) + created_at?: DateComparisonOperator + + @IsType([DateComparisonOperator]) + updated_at?: DateComparisonOperator +} diff --git a/packages/medusa/src/types/request.ts b/packages/medusa/src/types/request.ts new file mode 100644 index 0000000000..5a8cc58830 --- /dev/null +++ b/packages/medusa/src/types/request.ts @@ -0,0 +1,3 @@ +export type RequestContext = { + ip: string +} diff --git a/packages/medusa/src/types/shipping-tax-rate.ts b/packages/medusa/src/types/shipping-tax-rate.ts new file mode 100644 index 0000000000..ab60a189ec --- /dev/null +++ b/packages/medusa/src/types/shipping-tax-rate.ts @@ -0,0 +1,11 @@ +import { DateComparisonOperator } from "./common" + +/** + * The filters that can be applied when querying for shipping tax rates. + */ +export class FilterableShippingTaxRateProps { + shipping_option_id?: string | string[] + rate_id?: string | string[] + created_at?: DateComparisonOperator + updated_at?: DateComparisonOperator +} diff --git a/packages/medusa/src/types/tax-rate.ts b/packages/medusa/src/types/tax-rate.ts new file mode 100644 index 0000000000..7be9ba4e2a --- /dev/null +++ b/packages/medusa/src/types/tax-rate.ts @@ -0,0 +1,33 @@ +import { + DateComparisonOperator, + NumericalComparisonOperator, + StringComparisonOperator, +} from "./common" + +export type FilterableTaxRateProps = { + region_id?: string | string[] + code?: string | string[] | StringComparisonOperator + name?: string | string[] + rate?: number | NumericalComparisonOperator + created_at?: Date | DateComparisonOperator + updated_at?: Date | DateComparisonOperator + deleted_at?: Date | DateComparisonOperator +} + +export type UpdateTaxRateInput = { + region_id?: string + code?: string + name?: string + rate?: number | null +} + +export type CreateTaxRateInput = { + region_id: string + code: string + name: string + rate?: number | null +} + +export type TaxRateListByConfig = { + region_id?: string +} diff --git a/packages/medusa/src/types/tax-service.ts b/packages/medusa/src/types/tax-service.ts new file mode 100644 index 0000000000..e2d4b0f775 --- /dev/null +++ b/packages/medusa/src/types/tax-service.ts @@ -0,0 +1,39 @@ +/** + * The tax rate object as configured in Medusa. These may have an unspecified + * numerical rate as they may be used for lookup purposes in the tax provider + * plugin. + */ +export type TaxServiceRate = { + rate?: number | null + name: string + code: string | null +} + +/** + * The tax line properties for a given shipping method. + */ +export type ProviderShippingMethodTaxLine = { + rate: number + name: string + code: string | null + metadata?: JSON + shipping_method_id: string +} + +/** + * The tax line properties for a given line item. + */ +export type ProviderLineItemTaxLine = { + rate: number + name: string + code: string | null + item_id: string + metadata?: JSON +} + +/** + * A union type of the possible provider tax lines. + */ +export type ProviderTaxLine = + | ProviderLineItemTaxLine + | ProviderShippingMethodTaxLine diff --git a/packages/medusa/src/types/totals.ts b/packages/medusa/src/types/totals.ts new file mode 100644 index 0000000000..ea0378a3ca --- /dev/null +++ b/packages/medusa/src/types/totals.ts @@ -0,0 +1,45 @@ +import { LineItem } from "../models/line-item" + +/** The amount of a gift card allocated to a line item */ +export type GiftCardAllocation = { + amount: number + unit_amount: number +} + +/** The amount of a discount allocated to a line item */ +export type DiscountAllocation = { + amount: number + unit_amount: number +} + +/** + * A map of line item ids and its corresponding gift card and discount + * allocations + */ +export type LineAllocationsMap = { + [K: string]: { gift_card?: GiftCardAllocation; discount?: DiscountAllocation } +} + +/** + * Options to use for subtotal calculations + */ +export type SubtotalOptions = { + excludeNonDiscounts?: boolean +} + +/** + * Associates a line item and discount allocation. + */ +export type LineDiscount = { + lineItem: LineItem + variant: string + amount: number +} + +/** + * Associates a line item and discount allocation. + */ +export type LineDiscountAmount = { + item: LineItem + amount: number +} diff --git a/packages/medusa/src/utils/format-registration-name.js b/packages/medusa/src/utils/format-registration-name.js index 1830c0c3f3..85ef6f6158 100644 --- a/packages/medusa/src/utils/format-registration-name.js +++ b/packages/medusa/src/utils/format-registration-name.js @@ -24,6 +24,9 @@ function formatRegistrationName(fn) { case "repositories": namespace = "repositorys" break + case "strategies": + namespace = "strategys" + break default: break } diff --git a/packages/medusa/yarn.lock b/packages/medusa/yarn.lock index 1355c376b7..3a7564c1c7 100644 --- a/packages/medusa/yarn.lock +++ b/packages/medusa/yarn.lock @@ -32,6 +32,18 @@ dependencies: "@babel/highlight" "^7.16.0" +"@babel/code-frame@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.4", "@babel/compat-data@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.8.tgz#31560f9f29fdf1868de8cb55049538a1b9732a60" + integrity sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q== + "@babel/compat-data@^7.16.0": version "7.16.4" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e" @@ -67,6 +79,15 @@ jsesc "^2.5.1" source-map "^0.5.0" +"@babel/generator@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.8.tgz#359d44d966b8cd059d543250ce79596f792f2ebe" + integrity sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw== + dependencies: + "@babel/types" "^7.16.8" + jsesc "^2.5.1" + source-map "^0.5.0" + "@babel/helper-annotate-as-pure@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.0.tgz#9a1f0ebcda53d9a2d00108c4ceace6a5d5f1f08d" @@ -74,6 +95,31 @@ dependencies: "@babel/types" "^7.16.0" +"@babel/helper-annotate-as-pure@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" + integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz#38d138561ea207f0f69eb1626a418e4f7e6a580b" + integrity sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz#06e66c5f299601e6c7da350049315e83209d551b" + integrity sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA== + dependencies: + "@babel/compat-data" "^7.16.4" + "@babel/helper-validator-option" "^7.16.7" + browserslist "^4.17.5" + semver "^6.3.0" + "@babel/helper-compilation-targets@^7.16.0": version "7.16.3" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.3.tgz#5b480cd13f68363df6ec4dc8ac8e2da11363cbf0" @@ -96,6 +142,55 @@ "@babel/helper-replace-supers" "^7.16.0" "@babel/helper-split-export-declaration" "^7.16.0" +"@babel/helper-create-class-features-plugin@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.7.tgz#9c5b34b53a01f2097daf10678d65135c1b9f84ba" + integrity sha512-kIFozAvVfK05DM4EVQYKK+zteWvY85BFdGBRQBytRyY3y+6PX0DkDOn/CZ3lEuczCfrCxEzwt0YtP/87YPTWSw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-member-expression-to-functions" "^7.16.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + +"@babel/helper-create-regexp-features-plugin@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.7.tgz#0cb82b9bac358eb73bfbd73985a776bfa6b14d48" + integrity sha512-fk5A6ymfp+O5+p2yCkXAu5Kyj6v0xh0RBeNcAkYUMDvvAAoxvSKXn+Jb37t/yWFiQVDFK1ELpUTD8/aLhCPu+g== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + regexpu-core "^4.7.1" + +"@babel/helper-define-polyfill-provider@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.0.tgz#c5b10cf4b324ff840140bb07e05b8564af2ae971" + integrity sha512-7hfT8lUljl/tM3h+izTX/pO3W3frz2ok6Pk+gzys8iJqDfZrZy2pXjRTZAvG2YmfHun1X4q8/UZRLatMfqc5Tg== + dependencies: + "@babel/helper-compilation-targets" "^7.13.0" + "@babel/helper-module-imports" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/traverse" "^7.13.0" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + +"@babel/helper-environment-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" + integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-explode-assignable-expression@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz#12a6d8522fdd834f194e868af6354e8650242b7a" + integrity sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-function-name@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz#b7dd0797d00bbfee4f07e9c4ea5b0e30c8bb1481" @@ -105,6 +200,15 @@ "@babel/template" "^7.16.0" "@babel/types" "^7.16.0" +"@babel/helper-function-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" + integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== + dependencies: + "@babel/helper-get-function-arity" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/types" "^7.16.7" + "@babel/helper-get-function-arity@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz#0088c7486b29a9cb5d948b1a1de46db66e089cfa" @@ -112,6 +216,13 @@ dependencies: "@babel/types" "^7.16.0" +"@babel/helper-get-function-arity@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" + integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-hoist-variables@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz#4c9023c2f1def7e28ff46fc1dbcd36a39beaa81a" @@ -119,6 +230,13 @@ dependencies: "@babel/types" "^7.16.0" +"@babel/helper-hoist-variables@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" + integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-member-expression-to-functions@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz#29287040efd197c77636ef75188e81da8bccd5a4" @@ -126,6 +244,20 @@ dependencies: "@babel/types" "^7.16.0" +"@babel/helper-member-expression-to-functions@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz#42b9ca4b2b200123c3b7e726b0ae5153924905b0" + integrity sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" + integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-module-imports@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz#90538e60b672ecf1b448f5f4f5433d37e79a3ec3" @@ -147,6 +279,20 @@ "@babel/traverse" "^7.16.0" "@babel/types" "^7.16.0" +"@babel/helper-module-transforms@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz#7665faeb721a01ca5327ddc6bba15a5cb34b6a41" + integrity sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng== + dependencies: + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-simple-access" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + "@babel/helper-optimise-call-expression@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz#cecdb145d70c54096b1564f8e9f10cd7d193b338" @@ -154,11 +300,32 @@ dependencies: "@babel/types" "^7.16.0" +"@babel/helper-optimise-call-expression@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz#a34e3560605abbd31a18546bd2aad3e6d9a174f2" + integrity sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== +"@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.3": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" + integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== + +"@babel/helper-remap-async-to-generator@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz#29ffaade68a367e2ed09c90901986918d25e57e3" + integrity sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-wrap-function" "^7.16.8" + "@babel/types" "^7.16.8" + "@babel/helper-replace-supers@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz#73055e8d3cf9bcba8ddb55cad93fedc860f68f17" @@ -169,6 +336,17 @@ "@babel/traverse" "^7.16.0" "@babel/types" "^7.16.0" +"@babel/helper-replace-supers@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz#e9f5f5f32ac90429c1a4bdec0f231ef0c2838ab1" + integrity sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw== + dependencies: + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-member-expression-to-functions" "^7.16.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + "@babel/helper-simple-access@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz#21d6a27620e383e37534cf6c10bba019a6f90517" @@ -176,6 +354,20 @@ dependencies: "@babel/types" "^7.16.0" +"@babel/helper-simple-access@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz#d656654b9ea08dbb9659b69d61063ccd343ff0f7" + integrity sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-skip-transparent-expression-wrappers@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" + integrity sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-split-export-declaration@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz#29672f43663e936df370aaeb22beddb3baec7438" @@ -183,16 +375,43 @@ dependencies: "@babel/types" "^7.16.0" +"@babel/helper-split-export-declaration@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" + integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== + dependencies: + "@babel/types" "^7.16.7" + "@babel/helper-validator-identifier@^7.15.7": version "7.15.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + "@babel/helper-validator-option@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== +"@babel/helper-validator-option@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" + integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== + +"@babel/helper-wrap-function@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz#58afda087c4cd235de92f7ceedebca2c41274200" + integrity sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw== + dependencies: + "@babel/helper-function-name" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.8" + "@babel/types" "^7.16.8" + "@babel/helpers@^7.16.0": version "7.16.3" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.3.tgz#27fc64f40b996e7074dc73128c3e5c3e7f55c43c" @@ -211,11 +430,178 @@ chalk "^2.0.0" js-tokens "^4.0.0" +"@babel/highlight@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.7.tgz#81a01d7d675046f0d96f82450d9d9578bdfd6b0b" + integrity sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + "@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.0", "@babel/parser@^7.16.3": version "7.16.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.4.tgz#d5f92f57cf2c74ffe9b37981c0e72fee7311372e" integrity sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng== +"@babel/parser@^7.16.7", "@babel/parser@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.8.tgz#61c243a3875f7d0b0962b0543a33ece6ff2f1f17" + integrity sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw== + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz#4eda6d6c2a0aa79c70fa7b6da67763dfe2141050" + integrity sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz#cc001234dfc139ac45f6bcf801866198c8c72ff9" + integrity sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-proposal-optional-chaining" "^7.16.7" + +"@babel/plugin-proposal-async-generator-functions@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz#3bdd1ebbe620804ea9416706cd67d60787504bc8" + integrity sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-remap-async-to-generator" "^7.16.8" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-proposal-class-properties@^7.12.1", "@babel/plugin-proposal-class-properties@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz#925cad7b3b1a2fcea7e59ecc8eb5954f961f91b0" + integrity sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-proposal-class-static-block@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.7.tgz#712357570b612106ef5426d13dc433ce0f200c2a" + integrity sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-proposal-decorators@^7.12.1": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.16.7.tgz#922907d2e3e327f5b07d2246bcfc0bd438f360d2" + integrity sha512-DoEpnuXK14XV9btI1k8tzNGCutMclpj4yru8aXKoHlVmbO1s+2A+g2+h4JhcjrxkFJqzbymnLG6j/niOf3iFXQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-decorators" "^7.16.7" + +"@babel/plugin-proposal-dynamic-import@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz#c19c897eaa46b27634a00fee9fb7d829158704b2" + integrity sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-proposal-export-namespace-from@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz#09de09df18445a5786a305681423ae63507a6163" + integrity sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz#9732cb1d17d9a2626a08c5be25186c195b6fa6e8" + integrity sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-proposal-logical-assignment-operators@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz#be23c0ba74deec1922e639832904be0bea73cdea" + integrity sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz#141fc20b6857e59459d430c850a0011e36561d99" + integrity sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-proposal-numeric-separator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz#d6b69f4af63fb38b6ca2558442a7fb191236eba9" + integrity sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.7.tgz#94593ef1ddf37021a25bdcb5754c4a8d534b01d8" + integrity sha512-3O0Y4+dw94HA86qSg9IHfyPktgR7q3gpNVAeiKQd+8jBKFaU5NQS1Yatgo4wY+UFNuLjvxcSmzcsHqrhgTyBUA== + dependencies: + "@babel/compat-data" "^7.16.4" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.16.7" + +"@babel/plugin-proposal-optional-catch-binding@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz#c623a430674ffc4ab732fd0a0ae7722b67cb74cf" + integrity sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-proposal-optional-chaining@^7.14.2", "@babel/plugin-proposal-optional-chaining@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz#7cd629564724816c0e8a969535551f943c64c39a" + integrity sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-proposal-private-methods@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.7.tgz#e418e3aa6f86edd6d327ce84eff188e479f571e0" + integrity sha512-7twV3pzhrRxSwHeIvFE6coPgvo+exNDOiGUMg39o2LiLo1Y+4aKpfkcLGcg1UHonzorCt7SNXnoMyCnnIOA8Sw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-proposal-private-property-in-object@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz#b0b8cef543c2c3d57e59e2c611994861d46a3fce" + integrity sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-proposal-unicode-property-regex@^7.16.7", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz#635d18eb10c6214210ffc5ff4932552de08188a2" + integrity sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" @@ -230,13 +616,41 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.8.3": +"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-decorators@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.16.7.tgz#f66a0199f16de7c1ef5192160ccf5d069739e3d3" + integrity sha512-vQ+PxL+srA7g6Rx6I1e15m55gftknl2X8GCUW1JTlkTaXZLJOS0UcaY0eK9jYT7IYf4awn6qwyghVHLDz1WyMw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-import-meta@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" @@ -251,7 +665,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== @@ -265,7 +679,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.8.3": +"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== @@ -293,6 +707,20 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-typescript@^7.16.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.0.tgz#2feeb13d9334cc582ea9111d3506f773174179bb" @@ -300,6 +728,267 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" +"@babel/plugin-syntax-typescript@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz#39c9b55ee153151990fb038651d58d3fd03f98f8" + integrity sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-arrow-functions@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz#44125e653d94b98db76369de9c396dc14bef4154" + integrity sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-async-to-generator@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz#b83dff4b970cf41f1b819f8b49cc0cfbaa53a808" + integrity sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-remap-async-to-generator" "^7.16.8" + +"@babel/plugin-transform-block-scoped-functions@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz#4d0d57d9632ef6062cdf354bb717102ee042a620" + integrity sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-block-scoping@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz#f50664ab99ddeaee5bc681b8f3a6ea9d72ab4f87" + integrity sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-classes@^7.12.1", "@babel/plugin-transform-classes@^7.16.7", "@babel/plugin-transform-classes@^7.9.5": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz#8f4b9562850cd973de3b498f1218796eb181ce00" + integrity sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz#66dee12e46f61d2aae7a73710f591eb3df616470" + integrity sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-destructuring@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.7.tgz#ca9588ae2d63978a4c29d3f33282d8603f618e23" + integrity sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-dotall-regex@^7.16.7", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz#6b2d67686fab15fb6a7fd4bd895d5982cfc81241" + integrity sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-duplicate-keys@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz#2207e9ca8f82a0d36a5a67b6536e7ef8b08823c9" + integrity sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-exponentiation-operator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz#efa9862ef97e9e9e5f653f6ddc7b665e8536fe9b" + integrity sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-for-of@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz#649d639d4617dff502a9a158c479b3b556728d8c" + integrity sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-function-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz#5ab34375c64d61d083d7d2f05c38d90b97ec65cf" + integrity sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA== + dependencies: + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-instanceof@^7.12.1": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-instanceof/-/plugin-transform-instanceof-7.16.7.tgz#cedb7fb33e9fa25ace9cc2b020d2bb07bc584f11" + integrity sha512-DhH2rWEmDc+i9v3sVa4VIIFyKlMu3jPuJdwrq2Xcv9B+PxGkhdpyyNLJiBzZMyf3VVNN/voti03KY+C8lPh+Nw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz#254c9618c5ff749e87cb0c0cef1a0a050c0bdab1" + integrity sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-member-expression-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz#6e5dcf906ef8a098e630149d14c867dd28f92384" + integrity sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-modules-amd@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz#b28d323016a7daaae8609781d1f8c9da42b13186" + integrity sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g== + dependencies: + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-commonjs@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz#cdee19aae887b16b9d331009aa9a219af7c86afe" + integrity sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA== + dependencies: + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-simple-access" "^7.16.7" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-systemjs@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz#887cefaef88e684d29558c2b13ee0563e287c2d7" + integrity sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw== + dependencies: + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-umd@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz#23dad479fa585283dbd22215bff12719171e7618" + integrity sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ== + dependencies: + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz#7f860e0e40d844a02c9dcf9d84965e7dfd666252" + integrity sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + +"@babel/plugin-transform-new-target@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz#9967d89a5c243818e0800fdad89db22c5f514244" + integrity sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-object-super@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz#ac359cf8d32cf4354d27a46867999490b6c32a94" + integrity sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + +"@babel/plugin-transform-parameters@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz#a1721f55b99b736511cb7e0152f61f17688f331f" + integrity sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-property-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz#2dadac85155436f22c696c4827730e0fe1057a55" + integrity sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-regenerator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz#9e7576dc476cb89ccc5096fff7af659243b4adeb" + integrity sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q== + dependencies: + regenerator-transform "^0.14.2" + +"@babel/plugin-transform-reserved-words@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz#1d798e078f7c5958eec952059c460b220a63f586" + integrity sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-runtime@^7.12.1": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.8.tgz#3339368701103edae708f0fba9e4bfb70a3e5872" + integrity sha512-6Kg2XHPFnIarNweZxmzbgYnnWsXxkx9WQUVk2sksBRL80lBC1RAQV3wQagWxdCHiYHqPN+oenwNIuttlYgIbQQ== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + babel-plugin-polyfill-corejs2 "^0.3.0" + babel-plugin-polyfill-corejs3 "^0.5.0" + babel-plugin-polyfill-regenerator "^0.3.0" + semver "^6.3.0" + +"@babel/plugin-transform-shorthand-properties@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz#e8549ae4afcf8382f711794c0c7b6b934c5fbd2a" + integrity sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-spread@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz#a303e2122f9f12e0105daeedd0f30fb197d8ff44" + integrity sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + +"@babel/plugin-transform-sticky-regex@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz#c84741d4f4a38072b9a1e2e3fd56d359552e8660" + integrity sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-template-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz#f3d1c45d28967c8e80f53666fc9c3e50618217ab" + integrity sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-typeof-symbol@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz#9cdbe622582c21368bd482b660ba87d5545d4f7e" + integrity sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-transform-typescript@^7.16.0": version "7.16.1" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.1.tgz#cc0670b2822b0338355bc1b3d2246a42b8166409" @@ -309,6 +998,129 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript" "^7.16.0" +"@babel/plugin-transform-typescript@^7.16.7": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz#591ce9b6b83504903fa9dd3652c357c2ba7a1ee0" + integrity sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-typescript" "^7.16.7" + +"@babel/plugin-transform-unicode-escapes@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz#da8717de7b3287a2c6d659750c964f302b31ece3" + integrity sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/plugin-transform-unicode-regex@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz#0f7aa4a501198976e25e82702574c34cfebe9ef2" + integrity sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/polyfill@^7.8.7": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.12.1.tgz#1f2d6371d1261bbd961f3c5d5909150e12d0bd96" + integrity sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g== + dependencies: + core-js "^2.6.5" + regenerator-runtime "^0.13.4" + +"@babel/preset-env@^7.12.7": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.16.8.tgz#e682fa0bcd1cf49621d64a8956318ddfb9a05af9" + integrity sha512-9rNKgVCdwHb3z1IlbMyft6yIXIeP3xz6vWvGaLHrJThuEIqWfHb0DNBH9VuTgnDfdbUDhkmkvMZS/YMCtP7Elg== + dependencies: + "@babel/compat-data" "^7.16.8" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-option" "^7.16.7" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.16.7" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.16.7" + "@babel/plugin-proposal-async-generator-functions" "^7.16.8" + "@babel/plugin-proposal-class-properties" "^7.16.7" + "@babel/plugin-proposal-class-static-block" "^7.16.7" + "@babel/plugin-proposal-dynamic-import" "^7.16.7" + "@babel/plugin-proposal-export-namespace-from" "^7.16.7" + "@babel/plugin-proposal-json-strings" "^7.16.7" + "@babel/plugin-proposal-logical-assignment-operators" "^7.16.7" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.7" + "@babel/plugin-proposal-numeric-separator" "^7.16.7" + "@babel/plugin-proposal-object-rest-spread" "^7.16.7" + "@babel/plugin-proposal-optional-catch-binding" "^7.16.7" + "@babel/plugin-proposal-optional-chaining" "^7.16.7" + "@babel/plugin-proposal-private-methods" "^7.16.7" + "@babel/plugin-proposal-private-property-in-object" "^7.16.7" + "@babel/plugin-proposal-unicode-property-regex" "^7.16.7" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-transform-arrow-functions" "^7.16.7" + "@babel/plugin-transform-async-to-generator" "^7.16.8" + "@babel/plugin-transform-block-scoped-functions" "^7.16.7" + "@babel/plugin-transform-block-scoping" "^7.16.7" + "@babel/plugin-transform-classes" "^7.16.7" + "@babel/plugin-transform-computed-properties" "^7.16.7" + "@babel/plugin-transform-destructuring" "^7.16.7" + "@babel/plugin-transform-dotall-regex" "^7.16.7" + "@babel/plugin-transform-duplicate-keys" "^7.16.7" + "@babel/plugin-transform-exponentiation-operator" "^7.16.7" + "@babel/plugin-transform-for-of" "^7.16.7" + "@babel/plugin-transform-function-name" "^7.16.7" + "@babel/plugin-transform-literals" "^7.16.7" + "@babel/plugin-transform-member-expression-literals" "^7.16.7" + "@babel/plugin-transform-modules-amd" "^7.16.7" + "@babel/plugin-transform-modules-commonjs" "^7.16.8" + "@babel/plugin-transform-modules-systemjs" "^7.16.7" + "@babel/plugin-transform-modules-umd" "^7.16.7" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.16.8" + "@babel/plugin-transform-new-target" "^7.16.7" + "@babel/plugin-transform-object-super" "^7.16.7" + "@babel/plugin-transform-parameters" "^7.16.7" + "@babel/plugin-transform-property-literals" "^7.16.7" + "@babel/plugin-transform-regenerator" "^7.16.7" + "@babel/plugin-transform-reserved-words" "^7.16.7" + "@babel/plugin-transform-shorthand-properties" "^7.16.7" + "@babel/plugin-transform-spread" "^7.16.7" + "@babel/plugin-transform-sticky-regex" "^7.16.7" + "@babel/plugin-transform-template-literals" "^7.16.7" + "@babel/plugin-transform-typeof-symbol" "^7.16.7" + "@babel/plugin-transform-unicode-escapes" "^7.16.7" + "@babel/plugin-transform-unicode-regex" "^7.16.7" + "@babel/preset-modules" "^0.1.5" + "@babel/types" "^7.16.8" + babel-plugin-polyfill-corejs2 "^0.3.0" + babel-plugin-polyfill-corejs3 "^0.5.0" + babel-plugin-polyfill-regenerator "^0.3.0" + core-js-compat "^3.20.2" + semver "^6.3.0" + +"@babel/preset-modules@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" + integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + "@babel/preset-typescript@^7.13.0": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.0.tgz#b0b4f105b855fb3d631ec036cdc9d1ffd1fa5eac" @@ -318,6 +1130,22 @@ "@babel/helper-validator-option" "^7.14.5" "@babel/plugin-transform-typescript" "^7.16.0" +"@babel/preset-typescript@^7.16.0": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz#ab114d68bb2020afc069cd51b37ff98a046a70b9" + integrity sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-option" "^7.16.7" + "@babel/plugin-transform-typescript" "^7.16.7" + +"@babel/runtime@^7.15.4", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.6": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.7.tgz#03ff99f64106588c9c403c6ecb8c3bafbbdff1fa" + integrity sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/template@^7.16.0", "@babel/template@^7.3.3": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6" @@ -327,6 +1155,15 @@ "@babel/parser" "^7.16.0" "@babel/types" "^7.16.0" +"@babel/template@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + "@babel/traverse@^7.1.0", "@babel/traverse@^7.16.0", "@babel/traverse@^7.16.3": version "7.16.3" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.3.tgz#f63e8a938cc1b780f66d9ed3c54f532ca2d14787" @@ -342,6 +1179,22 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.8.tgz#bab2f2b09a5fe8a8d9cad22cbfe3ba1d126fef9c" + integrity sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.16.8" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/parser" "^7.16.8" + "@babel/types" "^7.16.8" + debug "^4.1.0" + globals "^11.1.0" + "@babel/types@^7.0.0", "@babel/types@^7.16.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3": version "7.16.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" @@ -350,6 +1203,14 @@ "@babel/helper-validator-identifier" "^7.15.7" to-fast-properties "^2.0.0" +"@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.4.4": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.8.tgz#0ba5da91dd71e0a4e7781a30f22770831062e3c1" + integrity sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -635,11 +1496,166 @@ "@types/yargs" "^15.0.0" chalk "^3.0.0" +"@jest/types@^27.4.2": + version "27.4.2" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.4.2.tgz#96536ebd34da6392c2b7c7737d693885b5dd44a5" + integrity sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + +"@medusajs/medusa-cli@^1.1.25": + version "1.1.26" + resolved "https://registry.yarnpkg.com/@medusajs/medusa-cli/-/medusa-cli-1.1.26.tgz#d6fa65aef548187e02fd71db2688276bf62d2084" + integrity sha512-V+kZr3ldqLumiwEr2slO7FrWHnpy1OjIhnL/ruCDZZTw/FDyru6302xWszEXCSt9N8MCM/OufXugfQ0Iwr7JuA== + dependencies: + "@babel/polyfill" "^7.8.7" + "@babel/runtime" "^7.9.6" + "@hapi/joi" "^16.1.8" + axios "^0.21.1" + chalk "^4.0.0" + configstore "5.0.1" + core-js "^3.6.5" + dotenv "^8.2.0" + execa "^5.1.1" + fs-exists-cached "^1.0.0" + fs-extra "^10.0.0" + hosted-git-info "^4.0.2" + inquirer "^8.0.0" + is-valid-path "^0.1.1" + joi-objectid "^3.0.1" + meant "^1.0.1" + medusa-core-utils "^0.1.27" + medusa-telemetry "^0.0.11" + netrc-parser "^3.1.6" + open "^8.0.6" + ora "^5.4.1" + pg-god "^1.0.11" + prompts "^2.4.1" + regenerator-runtime "^0.13.5" + resolve-cwd "^3.0.0" + stack-trace "^0.0.10" + ulid "^2.3.0" + url "^0.11.0" + winston "^3.3.3" + yargs "^15.3.1" + "@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": version "2.1.8-no-fsevents.3" resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz#323d72dd25103d0c4fbdce89dadf574a787b1f9b" integrity sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ== +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@oclif/command@^1", "@oclif/command@^1.8.15": + version "1.8.16" + resolved "https://registry.yarnpkg.com/@oclif/command/-/command-1.8.16.tgz#bea46f81b2061b47e1cda318a0b923e62ca4cc0c" + integrity sha512-rmVKYEsKzurfRU0xJz+iHelbi1LGlihIWZ7Qvmb/CBz1EkhL7nOkW4SVXmG2dA5Ce0si2gr88i6q4eBOMRNJ1w== + dependencies: + "@oclif/config" "^1.18.2" + "@oclif/errors" "^1.3.5" + "@oclif/help" "^1.0.1" + "@oclif/parser" "^3.8.6" + debug "^4.1.1" + semver "^7.3.2" + +"@oclif/config@1.18.2", "@oclif/config@^1", "@oclif/config@^1.18.2": + version "1.18.2" + resolved "https://registry.yarnpkg.com/@oclif/config/-/config-1.18.2.tgz#5bfe74a9ba6a8ca3dceb314a81bd9ce2e15ebbfe" + integrity sha512-cE3qfHWv8hGRCP31j7fIS7BfCflm/BNZ2HNqHexH+fDrdF2f1D5S8VmXWLC77ffv3oDvWyvE9AZeR0RfmHCCaA== + dependencies: + "@oclif/errors" "^1.3.3" + "@oclif/parser" "^3.8.0" + debug "^4.1.1" + globby "^11.0.1" + is-wsl "^2.1.1" + tslib "^2.0.0" + +"@oclif/errors@1.3.5", "@oclif/errors@^1.2.2", "@oclif/errors@^1.3.3", "@oclif/errors@^1.3.5": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@oclif/errors/-/errors-1.3.5.tgz#a1e9694dbeccab10fe2fe15acb7113991bed636c" + integrity sha512-OivucXPH/eLLlOT7FkCMoZXiaVYf8I/w1eTAM1+gKzfhALwWTusxEx7wBmW0uzvkSg/9ovWLycPaBgJbM3LOCQ== + dependencies: + clean-stack "^3.0.0" + fs-extra "^8.1" + indent-string "^4.0.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +"@oclif/help@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@oclif/help/-/help-1.0.1.tgz#fd96a3dd9fb2314479e6c8584c91b63754a7dff5" + integrity sha512-8rsl4RHL5+vBUAKBL6PFI3mj58hjPCp2VYyXD4TAa7IMStikFfOH2gtWmqLzIlxAED2EpD0dfYwo9JJxYsH7Aw== + dependencies: + "@oclif/config" "1.18.2" + "@oclif/errors" "1.3.5" + chalk "^4.1.2" + indent-string "^4.0.0" + lodash "^4.17.21" + string-width "^4.2.0" + strip-ansi "^6.0.0" + widest-line "^3.1.0" + wrap-ansi "^6.2.0" + +"@oclif/linewrap@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@oclif/linewrap/-/linewrap-1.0.0.tgz#aedcb64b479d4db7be24196384897b5000901d91" + integrity sha512-Ups2dShK52xXa8w6iBWLgcjPJWjais6KPJQq3gQ/88AY6BXoTX+MIGFPrWQO1KLMiQfoTpcLnUwloN4brrVUHw== + +"@oclif/parser@^3.8.0", "@oclif/parser@^3.8.6": + version "3.8.6" + resolved "https://registry.yarnpkg.com/@oclif/parser/-/parser-3.8.6.tgz#d5a108af9c708a051cc6b1d27d47359d75f41236" + integrity sha512-tXb0NKgSgNxmf6baN6naK+CCwOueaFk93FG9u202U7mTBHUKsioOUlw1SG/iPi9aJM3WE4pHLXmty59pci0OEw== + dependencies: + "@oclif/errors" "^1.2.2" + "@oclif/linewrap" "^1.0.0" + chalk "^4.1.0" + tslib "^2.0.0" + +"@oclif/plugin-help@^3": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@oclif/plugin-help/-/plugin-help-3.3.1.tgz#36adb4e0173f741df409bb4b69036d24a53bfb24" + integrity sha512-QuSiseNRJygaqAdABYFWn/H1CwIZCp9zp/PLid6yXvy6VcQV7OenEFF5XuYaCvSARe2Tg9r8Jqls5+fw1A9CbQ== + dependencies: + "@oclif/command" "^1.8.15" + "@oclif/config" "1.18.2" + "@oclif/errors" "1.3.5" + "@oclif/help" "^1.0.1" + chalk "^4.1.2" + indent-string "^4.0.0" + lodash "^4.17.21" + string-width "^4.2.0" + strip-ansi "^6.0.0" + widest-line "^3.1.0" + wrap-ansi "^6.2.0" + +"@oclif/screen@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@oclif/screen/-/screen-1.0.4.tgz#b740f68609dfae8aa71c3a6cab15d816407ba493" + integrity sha512-60CHpq+eqnTxLZQ4PGHYNwUX572hgpMHGPtTWMjdTMsAvlm69lZV/4ly6O3sAYkomo4NggGcomrDpBe34rxUqw== + "@sideway/address@^4.1.0": version "4.1.2" resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.2.tgz#811b84333a335739d3969cfc434736268170cad1" @@ -770,6 +1786,21 @@ "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^27.0.3": + version "27.0.3" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.0.3.tgz#0cf9dfe9009e467f70a342f0f94ead19842a783a" + integrity sha512-cmmwv9t7gBYt7hNKH5Spu7Kuu/DotGa+Ff+JGRKZ4db5eh8PnKS4LuebJ3YLUoyOyIHraTGyULn23YtEAm0VSg== + dependencies: + jest-diff "^27.0.0" + pretty-format "^27.0.0" + "@types/jsonwebtoken@^8.5.5": version "8.5.6" resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-8.5.6.tgz#1913e5a61e70a192c5a444623da4901a7b1a9d42" @@ -837,6 +1868,13 @@ dependencies: "@types/yargs-parser" "*" +"@types/yargs@^16.0.0": + version "16.0.4" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" + integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== + dependencies: + "@types/yargs-parser" "*" + abab@^2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" @@ -915,7 +1953,12 @@ ansi-colors@^4.1.1: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== -ansi-escapes@^4.2.1: +ansi-escapes@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== + +ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== @@ -944,13 +1987,23 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0, ansi-styles@^4.1.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0, ansi-styles@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +ansicolors@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/ansicolors/-/ansicolors-0.3.2.tgz#665597de86a9ffe3aa9bfbe6cae5c6ea426b4979" + integrity sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk= + anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" @@ -1017,6 +2070,11 @@ array-flatten@1.1.1: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" @@ -1054,6 +2112,11 @@ async@^3.1.0: resolved "https://registry.yarnpkg.com/async/-/async-3.2.2.tgz#2eb7671034bb2194d45d30e31e24ec7e7f9670cd" integrity sha512-H0E+qZaDEfx/FY4t7iLRv1W2fFI6+pyCeTw1uN20AQPiwqwM6ojPxHxdLv4z8hi2DtnW9BOckSspLucW7pIE5g== +async@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.3.tgz#ac53dafd3f4720ee9e8a160628f18ea91df196c9" + integrity sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -1082,6 +2145,21 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== +axios-retry@^3.1.9: + version "3.2.4" + resolved "https://registry.yarnpkg.com/axios-retry/-/axios-retry-3.2.4.tgz#f447a53c3456f5bfeca18f20c3a3272207d082ae" + integrity sha512-Co3UXiv4npi6lM963mfnuH90/YFLKWWDmoBYfxkHT5xtkSSWNqK9zdG3fw5/CP/dsoKB5aMMJCsgab+tp1OxLQ== + dependencies: + "@babel/runtime" "^7.15.4" + is-retry-allowed "^2.2.0" + +axios@^0.21.1: + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== + dependencies: + follow-redirects "^1.14.0" + babel-jest@^25.5.1: version "25.5.1" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-25.5.1.tgz#bc2e6101f849d6f6aec09720ffc7bc5332e62853" @@ -1096,6 +2174,13 @@ babel-jest@^25.5.1: graceful-fs "^4.2.4" slash "^3.0.0" +babel-plugin-dynamic-import-node@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + babel-plugin-istanbul@^6.0.0: version "6.1.1" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" @@ -1116,6 +2201,37 @@ babel-plugin-jest-hoist@^25.5.0: "@babel/types" "^7.3.3" "@types/babel__traverse" "^7.0.6" +babel-plugin-polyfill-corejs2@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.0.tgz#407082d0d355ba565af24126fb6cb8e9115251fd" + integrity sha512-wMDoBJ6uG4u4PNFh72Ty6t3EgfA91puCuAwKIazbQlci+ENb/UU9A3xG5lutjUIiXCIn1CY5L15r9LimiJyrSA== + dependencies: + "@babel/compat-data" "^7.13.11" + "@babel/helper-define-polyfill-provider" "^0.3.0" + semver "^6.1.1" + +babel-plugin-polyfill-corejs3@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.0.tgz#f81371be3fe499d39e074e272a1ef86533f3d268" + integrity sha512-Hcrgnmkf+4JTj73GbK3bBhlVPiLL47owUAnoJIf69Hakl3q+KfodbDXiZWGMM7iqCZTxCG3Z2VRfPNYES4rXqQ== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.0" + core-js-compat "^3.20.0" + +babel-plugin-polyfill-regenerator@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.0.tgz#9ebbcd7186e1a33e21c5e20cae4e7983949533be" + integrity sha512-dhAPTDLGoMW5/84wkgwiLRwMnio2i1fUe53EuvtKMv0pn2p3S8OCoV1xAzfJPl0KOX7IB89s2ib85vbYiea3jg== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.0" + +babel-plugin-transform-typescript-metadata@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-typescript-metadata/-/babel-plugin-transform-typescript-metadata-0.3.2.tgz#7a327842d8c36ffe07ee1b5276434e56c297c9b7" + integrity sha512-mWEvCQTgXQf48yDqgN7CH50waTyYBeP2Lpqx4nNWab9sxEpdXVeKgfj1qYI2/TgUPQtNFZ85i3PemRtnXVYYJg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + babel-preset-current-node-syntax@^0.1.2: version "0.1.4" resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.4.tgz#826f1f8e7245ad534714ba001f84f7e906c3b615" @@ -1141,11 +2257,32 @@ babel-preset-jest@^25.5.0: babel-plugin-jest-hoist "^25.5.0" babel-preset-current-node-syntax "^0.1.2" +babel-preset-medusa-package@^1.1.19: + version "1.1.19" + resolved "https://registry.yarnpkg.com/babel-preset-medusa-package/-/babel-preset-medusa-package-1.1.19.tgz#6b761cdf16bae007aa779610951c64627bfefcb7" + integrity sha512-UZemPhNkoLhO4bVLi2QddqD28o4q7hFHHJcbgL68XENS66KchjBXeo5Fng63KALJv+RRe5rqoyY+J/JPdHLGbw== + dependencies: + "@babel/plugin-proposal-class-properties" "^7.12.1" + "@babel/plugin-proposal-decorators" "^7.12.1" + "@babel/plugin-proposal-optional-chaining" "^7.14.2" + "@babel/plugin-transform-classes" "^7.12.1" + "@babel/plugin-transform-instanceof" "^7.12.1" + "@babel/plugin-transform-runtime" "^7.12.1" + "@babel/preset-env" "^7.12.7" + "@babel/preset-typescript" "^7.16.0" + babel-plugin-transform-typescript-metadata "^0.3.1" + core-js "^3.7.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" @@ -1178,6 +2315,15 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== +bl@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + block-stream@*: version "0.0.9" resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" @@ -1201,7 +2347,7 @@ body-parser@1.19.0, body-parser@^1.19.0: raw-body "2.4.0" type-is "~1.6.17" -boxen@^5.0.0: +boxen@^5.0.0, boxen@^5.0.1: version "5.1.2" resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50" integrity sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ== @@ -1269,6 +2415,17 @@ browserslist@^4.17.5: node-releases "^2.0.1" picocolors "^1.0.0" +browserslist@^4.19.1: + version "4.19.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.19.1.tgz#4ac0435b35ab655896c31d53018b6dd5e9e4c9a3" + integrity sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A== + dependencies: + caniuse-lite "^1.0.30001286" + electron-to-chromium "^1.4.17" + escalade "^3.1.1" + node-releases "^2.0.1" + picocolors "^1.0.0" + bser@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" @@ -1291,6 +2448,14 @@ buffer-writer@2.0.0: resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + bull@^3.12.1: version "3.29.3" resolved "https://registry.yarnpkg.com/bull/-/bull-3.29.3.tgz#5b0059b172685b0d6f011d56214e1898ff3a7a0b" @@ -1384,6 +2549,11 @@ caniuse-lite@^1.0.30001280: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001282.tgz#38c781ee0a90ccfe1fe7fefd00e43f5ffdcb96fd" integrity sha512-YhF/hG6nqBEllymSIjLtR2iWDDnChvhnVJqp+vloyt2tEHFG1yBR+ac2B/rOw0qOK0m0lEXU2dv4E/sMk5P9Kg== +caniuse-lite@^1.0.30001286: + version "1.0.30001298" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001298.tgz#0e690039f62e91c3ea581673d716890512e7ec52" + integrity sha512-AcKqikjMLlvghZL/vfTHorlQsLDhGRalYf1+GmWCf5SCMziSGjRYQW/JEksj14NaYHIR6KIhrFAy0HV5C25UzQ== + capture-exit@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" @@ -1391,6 +2561,14 @@ capture-exit@^2.0.0: dependencies: rsvp "^4.8.4" +cardinal@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/cardinal/-/cardinal-2.1.1.tgz#7cc1055d822d212954d07b085dea251cc7bc5505" + integrity sha1-fMEFXYItISlU0HsIXeolHMe8VQU= + dependencies: + ansicolors "~0.3.2" + redeyed "~2.1.0" + caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" @@ -1413,7 +2591,7 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0, chalk@^4.1.0: +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -1421,6 +2599,11 @@ chalk@^4.0.0, chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + chokidar@^3.4.0, chokidar@^3.4.2, chokidar@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" @@ -1446,6 +2629,11 @@ ci-info@^2.0.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== +ci-info@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" + integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== + class-transformer@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336" @@ -1469,11 +2657,74 @@ class-validator@^0.13.1: libphonenumber-js "^1.9.43" validator "^13.7.0" +clean-stack@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-3.0.1.tgz#155bf0b2221bf5f4fba89528d24c5953f17fe3a8" + integrity sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg== + dependencies: + escape-string-regexp "4.0.0" + cli-boxes@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-progress@^3.4.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/cli-progress/-/cli-progress-3.10.0.tgz#63fd9d6343c598c93542fdfa3563a8b59887d78a" + integrity sha512-kLORQrhYCAtUPLZxqsAt2YJGOvRdt34+O6jl5cQGb7iF3dM55FQZlTR+rQyIK9JUcO9bBMwZsTlND+3dmFU2Cw== + dependencies: + string-width "^4.2.0" + +cli-spinners@^2.5.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" + integrity sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g== + +cli-ux@^5.4.9: + version "5.6.7" + resolved "https://registry.yarnpkg.com/cli-ux/-/cli-ux-5.6.7.tgz#32ef9e6cb2b457be834280cc799028a11c8235a8" + integrity sha512-dsKAurMNyFDnO6X1TiiRNiVbL90XReLKcvIq4H777NMqXGBxBws23ag8ubCJE97vVZEgWG2eSUhsyLf63Jv8+g== + dependencies: + "@oclif/command" "^1.8.15" + "@oclif/errors" "^1.3.5" + "@oclif/linewrap" "^1.0.0" + "@oclif/screen" "^1.0.4" + ansi-escapes "^4.3.0" + ansi-styles "^4.2.0" + cardinal "^2.1.1" + chalk "^4.1.0" + clean-stack "^3.0.0" + cli-progress "^3.4.0" + extract-stack "^2.0.0" + fs-extra "^8.1" + hyperlinker "^1.0.0" + indent-string "^4.0.0" + is-wsl "^2.2.0" + js-yaml "^3.13.1" + lodash "^4.17.21" + natural-orderby "^2.0.1" + object-treeify "^1.1.4" + password-prompt "^1.1.2" + semver "^7.3.2" + string-width "^4.2.0" + strip-ansi "^6.0.0" + supports-color "^8.1.0" + supports-hyperlinks "^2.1.0" + tslib "^2.0.0" + +cli-width@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" + integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== + cliui@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" @@ -1490,6 +2741,11 @@ clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + cluster-key-slot@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" @@ -1558,7 +2814,7 @@ color@^3.1.3: color-convert "^1.9.3" color-string "^1.6.0" -colors@^1.2.1: +colors@1.4.0, colors@^1.2.1: version "1.4.0" resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== @@ -1603,7 +2859,7 @@ concat-stream@^1.5.2: readable-stream "^2.2.2" typedarray "^0.0.6" -configstore@^5.0.1: +configstore@5.0.1, configstore@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== @@ -1677,11 +2933,29 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= +core-js-compat@^3.20.0, core-js-compat@^3.20.2: + version "3.20.2" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.20.2.tgz#d1ff6936c7330959b46b2e08b122a8b14e26140b" + integrity sha512-qZEzVQ+5Qh6cROaTPFLNS4lkvQ6mBzE3R6A6EEpssj7Zr2egMHgsy4XapdifqJDGC9CBiNv7s+ejI96rLNQFdg== + dependencies: + browserslist "^4.19.1" + semver "7.0.0" + +core-js@^2.6.5: + version "2.6.12" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" + integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== + core-js@^3.6.5: version "3.19.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.19.1.tgz#f6f173cae23e73a7d88fa23b6e9da329276c6641" integrity sha512-Tnc7E9iKd/b/ff7GFbhwPVzJzPztGrChB8X8GLqoYGdEOG8IpLnK1xPyo3ZoO3HsK6TodJS58VGPOxA+hLHQMg== +core-js@^3.7.0: + version "3.20.2" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.20.2.tgz#46468d8601eafc8b266bd2dd6bf9dee622779581" + integrity sha512-nuqhq11DcOAbFBV4zCbKeGbKQsUDRqTX0oqx7AttUBuqe3h20ixsE039QHelbL6P4h+9kytVqyEtyZ6gsiwEYw== + core-util-is@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -1831,11 +3105,23 @@ deepmerge@^4.2.2: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== +defaults@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" + integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= + dependencies: + clone "^1.0.2" + defer-to-connect@^1.0.1: version "1.1.3" resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -1918,6 +3204,18 @@ diff-sequences@^25.2.6: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg== +diff-sequences@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.4.0.tgz#d783920ad8d06ec718a060d00196dfef25b132a5" + integrity sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + doctrine@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" @@ -1925,6 +3223,11 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dom-walk@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" + integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== + domexception@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" @@ -1974,6 +3277,11 @@ electron-to-chromium@^1.3.896: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.904.tgz#52a353994faeb0f2a9fab3606b4e0614d1af7b58" integrity sha512-x5uZWXcVNYkTh4JubD7KSC1VMKz0vZwJUqVwY3ihsW0bst1BXDe494Uqbg3Y0fDGVjJqA8vEeGuvO5foyH2+qw== +electron-to-chromium@^1.4.17: + version "1.4.40" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.40.tgz#f5dbced7bfbc7072e5e7ca5487f8f9a42c8bc768" + integrity sha512-j+eVIyQGt2EU5xPWUblhpp5P5z5xyAdRgzogBgfe2F5JGV17gr9pfzWBua6DlPL00LavbOjxubWkWkbVQe9Wlw== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -2060,6 +3368,11 @@ escape-html@~1.0.3: resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= +escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -2070,11 +3383,6 @@ escape-string-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== -escape-string-regexp@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - escodegen@^1.11.1: version "1.14.3" resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" @@ -2167,7 +3475,7 @@ espree@^7.3.0, espree@^7.3.1: acorn-jsx "^5.3.1" eslint-visitor-keys "^1.3.0" -esprima@^4.0.0, esprima@^4.0.1: +esprima@^4.0.0, esprima@^4.0.1, esprima@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== @@ -2211,6 +3519,19 @@ exec-sh@^0.3.2: resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== +execa@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50" + integrity sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw== + dependencies: + cross-spawn "^6.0.0" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + execa@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" @@ -2240,6 +3561,21 @@ execa@^3.2.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" +execa@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -2340,6 +3676,15 @@ extend@^3.0.0, extend@~3.0.2: resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + extglob@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" @@ -2354,6 +3699,11 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" +extract-stack@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/extract-stack/-/extract-stack-2.0.0.tgz#11367bc865bfcd9bc0db3123e5edb57786f11f9b" + integrity sha512-AEo4zm+TenK7zQorGK1f9mJ8L14hnTDi2ZQPR+Mub1NX8zimka1mXpV5LpH8x9HoUmFSHZCfLHqWvp0Y4FxxzQ== + extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -2369,6 +3719,17 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-glob@^3.2.9: + version "3.2.10" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.10.tgz#2734f83baa7f43b7fd41e13bc34438f4ffe284ee" + integrity sha512-s9nFhFnvR63wls6/kM88kQqDhMu0AfdjqouE2l5GVQPbqLgyFjjU5ry/r2yKsJxpb9Py1EYNqieFrmMaX4v++A== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -2379,6 +3740,13 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fastq@^1.6.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + fb-watchman@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" @@ -2405,6 +3773,13 @@ fengari@^0.1.4: sprintf-js "^1.1.1" tmp "^0.0.33" +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -2468,6 +3843,11 @@ fn.name@1.x.x: resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== +follow-redirects@^1.14.0: + version "1.14.7" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685" + integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ== + for-each@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" @@ -2530,6 +3910,24 @@ fs-exists-cached@^1.0.0: resolved "https://registry.yarnpkg.com/fs-exists-cached/-/fs-exists-cached-1.0.0.tgz#cf25554ca050dc49ae6656b41de42258989dcbce" integrity sha1-zyVVTKBQ3EmuZla0HeQiWJidy84= +fs-extra@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" + integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs-extra@^8.1: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-minipass@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" @@ -2615,6 +4013,11 @@ get-port@^5.1.1: resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== +get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + get-stream@^4.0.0, get-stream@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -2629,6 +4032,11 @@ get-stream@^5.0.0, get-stream@^5.1.0: dependencies: pump "^3.0.0" +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" @@ -2675,6 +4083,14 @@ global-dirs@^3.0.0: dependencies: ini "2.0.0" +global@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" + integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== + dependencies: + min-document "^2.19.0" + process "^0.11.10" + globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" @@ -2687,6 +4103,18 @@ globals@^13.6.0, globals@^13.9.0: dependencies: type-fest "^0.20.2" +globby@^11.0.1: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + got@^9.6.0: version "9.6.0" resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" @@ -2709,6 +4137,11 @@ graceful-fs@^4.1.2, graceful-fs@^4.2.4: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== +graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.9" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" + integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== + growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" @@ -2807,6 +4240,13 @@ hosted-git-info@^2.1.4: resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== +hosted-git-info@^4.0.2: + version "4.1.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" + integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== + dependencies: + lru-cache "^6.0.0" + html-encoding-sniffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" @@ -2860,13 +4300,28 @@ human-signals@^1.1.1: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== -iconv-lite@0.4.24, iconv-lite@^0.4.4: +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +hyperlinker@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hyperlinker/-/hyperlinker-1.0.0.tgz#23dc9e38a206b208ee49bc2d6c8ef47027df0c0e" + integrity sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ== + +iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + ignore-by-default@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" @@ -2884,6 +4339,11 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + import-fresh@^3.0.0, import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -2910,6 +4370,11 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -2918,7 +4383,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -2938,6 +4403,26 @@ ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== +inquirer@^8.0.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.0.tgz#f44f008dd344bbfc4b30031f45d984e034a3ac3a" + integrity sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.1" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.21" + mute-stream "0.0.8" + ora "^5.4.1" + run-async "^2.4.0" + rxjs "^7.2.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + internal-slot@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" @@ -3054,6 +4539,13 @@ is-core-module@^2.2.0: dependencies: has "^1.0.3" +is-core-module@^2.8.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" + integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== + dependencies: + has "^1.0.3" + is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -3093,7 +4585,7 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2: is-data-descriptor "^1.0.0" kind-of "^6.0.2" -is-docker@^2.0.0: +is-docker@^2.0.0, is-docker@^2.1.1, is-docker@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== @@ -3110,6 +4602,11 @@ is-extendable@^1.0.1: dependencies: is-plain-object "^2.0.4" +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -3132,6 +4629,13 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== +is-glob@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + integrity sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM= + dependencies: + is-extglob "^1.0.0" + is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -3147,6 +4651,18 @@ is-installed-globally@^0.4.0: global-dirs "^3.0.0" is-path-inside "^3.0.2" +is-interactive@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" + integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== + +is-invalid-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-invalid-path/-/is-invalid-path-0.1.0.tgz#307a855b3cf1a938b44ea70d2c61106053714f34" + integrity sha1-MHqFWzzxqTi0TqcNLGEQYFNxTzQ= + dependencies: + is-glob "^2.0.0" + is-nan@^1.3.0: version "1.3.2" resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" @@ -3214,6 +4730,11 @@ is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-retry-allowed@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz#88f34cbd236e043e71b6932d09b0c65fb7b4d71d" + integrity sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg== + is-shared-array-buffer@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" @@ -3248,6 +4769,18 @@ is-typedarray@^1.0.0, is-typedarray@~1.0.0: resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +is-valid-path@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-valid-path/-/is-valid-path-0.1.1.tgz#110f9ff74c37f663e1ec7915eb451f2db93ac9df" + integrity sha1-EQ+f90w39mPh7HkV60UfLbk6yd8= + dependencies: + is-invalid-path "^0.1.0" + is-weakref@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.1.tgz#842dba4ec17fa9ac9850df2d6efbc1737274f2a2" @@ -3260,7 +4793,7 @@ is-windows@^1.0.2: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -is-wsl@^2.1.1: +is-wsl@^2.1.1, is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== @@ -3430,6 +4963,16 @@ jest-diff@^25.5.0: jest-get-type "^25.2.6" pretty-format "^25.5.0" +jest-diff@^27.0.0: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.4.2.tgz#786b2a5211d854f848e2dcc1e324448e9481f36f" + integrity sha512-ujc9ToyUZDh9KcqvQDkk/gkbf6zSaeEg9AiBxtttXW59H/AcqEYp1ciXAtJp+jXWva5nAf/ePtSsgWwE5mqp4Q== + dependencies: + chalk "^4.0.0" + diff-sequences "^27.4.0" + jest-get-type "^27.4.0" + pretty-format "^27.4.2" + jest-docblock@^25.3.0: version "25.3.0" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-25.3.0.tgz#8b777a27e3477cd77a168c05290c471a575623ef" @@ -3477,6 +5020,11 @@ jest-get-type@^25.2.6: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877" integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig== +jest-get-type@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.4.0.tgz#7503d2663fffa431638337b3998d39c5e928e9b5" + integrity sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ== + jest-haste-map@^25.5.1: version "25.5.1" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-25.5.1.tgz#1df10f716c1d94e60a1ebf7798c9fb3da2620943" @@ -3801,6 +5349,11 @@ jsesc@^2.5.1: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + json-buffer@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" @@ -3843,6 +5396,22 @@ json5@^2.1.2: dependencies: minimist "^1.2.5" +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + jsonwebtoken@^8.2.0, jsonwebtoken@^8.5.1: version "8.5.1" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" @@ -3972,6 +5541,11 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + lodash.defaults@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" @@ -4042,6 +5616,14 @@ lodash@^4.17.19, lodash@^4.17.21: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + logform@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/logform/-/logform-2.3.0.tgz#a3997a05985de2ebd325ae0d166dffc9c6fe6b57" @@ -4053,6 +5635,17 @@ logform@^2.2.0: safe-stable-stringify "^1.1.0" triple-beam "^1.3.0" +logform@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/logform/-/logform-2.3.2.tgz#68babe6a74ab09a1fd15a9b1e6cbc7713d41cb5b" + integrity sha512-V6JiPThZzTsbVRspNO6TmHkR99oqYTs8fivMBYQkjZj6rxW92KxtDCPE6IkAk1DNBnYKNkjm4jYBm6JDUcyhOA== + dependencies: + colors "1.4.0" + fecha "^4.2.0" + ms "^2.1.1" + safe-stable-stringify "^1.1.0" + triple-beam "^1.3.0" + lolex@^5.0.0: version "5.1.2" resolved "https://registry.yarnpkg.com/lolex/-/lolex-5.1.2.tgz#953694d098ce7c07bc5ed6d0e42bc6c0c6d5a367" @@ -4123,11 +5716,63 @@ math-random@^1.0.1: resolved "https://registry.yarnpkg.com/math-random/-/math-random-1.0.4.tgz#5dd6943c938548267016d4e34f057583080c514c" integrity sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A== +meant@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/meant/-/meant-1.0.3.tgz#67769af9de1d158773e928ae82c456114903554c" + integrity sha512-88ZRGcNxAq4EH38cQ4D85PM57pikCwS8Z99EWHODxN7KBY+UuPiqzRTtZzS8KTXO/ywSWbdjjJST2Hly/EQxLw== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= +medusa-core-utils@^0.1.27: + version "0.1.39" + resolved "https://registry.yarnpkg.com/medusa-core-utils/-/medusa-core-utils-0.1.39.tgz#d57816c9bd43f9a92883650c1e66add1665291df" + integrity sha512-R8+U1ile7if+nR6Cjh5exunx0ETV0OfkWUUBUpz1KmHSDv0V0CcvQqU9lcZesPFDEbu3Y2iEjsCqidVA4nG2nQ== + dependencies: + "@hapi/joi" "^16.1.8" + joi-objectid "^3.0.1" + +medusa-core-utils@^1.1.31: + version "1.1.31" + resolved "https://registry.yarnpkg.com/medusa-core-utils/-/medusa-core-utils-1.1.31.tgz#6cfc89566c2107faedf0f9128f2643b34b201455" + integrity sha512-nMAmdjm2HoizOskSOyK/KK7dJ3ccC86+dPbT5Q4AeJ9bTJVCTOFnkUMEScuSM5pXx1y8k+yxXRBvrv/Thh2OTw== + dependencies: + joi "^17.3.0" + joi-objectid "^3.0.1" + +medusa-interfaces@^1.1.32: + version "1.1.32" + resolved "https://registry.yarnpkg.com/medusa-interfaces/-/medusa-interfaces-1.1.32.tgz#cc7c460072aea5fd0c2da23cd780c15b2aa96029" + integrity sha512-7E9pEswnehWWSO22StHINJ/IOxBSsRarGS9ApHRujPMb/zf1xPnS0l39Rvz2Vb/gpsbzz9iC3btD3falcugQMQ== + dependencies: + medusa-core-utils "^1.1.31" + +medusa-telemetry@^0.0.11: + version "0.0.11" + resolved "https://registry.yarnpkg.com/medusa-telemetry/-/medusa-telemetry-0.0.11.tgz#1d80b0e3d73b456fae243027c65cd6c212584971" + integrity sha512-YZYGeG5SOOuP3lYM4g1yMoHUem1GK5ZfqRTeydDmZUGoA7zJvprqXQER6lcc+/FLv0kKr74K7MmtzBBlBRJl3g== + dependencies: + axios "^0.21.1" + axios-retry "^3.1.9" + boxen "^5.0.1" + ci-info "^3.2.0" + configstore "5.0.1" + global "^4.4.0" + is-docker "^2.2.1" + remove-trailing-slash "^0.1.1" + uuid "^8.3.2" + +medusa-test-utils@^1.1.35: + version "1.1.36" + resolved "https://registry.yarnpkg.com/medusa-test-utils/-/medusa-test-utils-1.1.36.tgz#267f03c3dafc34fd1334c5eccc8d1572f0159bfa" + integrity sha512-LNnsOa7dnEoiQF5uILTA9g7NAWKnQKCMxrs6XxEJsJUqioDiR9MxTfkfRtvyVfQE2AEMF79QH8jQpDY5ZGJFUA== + dependencies: + "@babel/plugin-transform-classes" "^7.9.5" + medusa-core-utils "^1.1.31" + randomatic "^3.1.1" + merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -4138,6 +5783,11 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + methods@^1.1.1, methods@^1.1.2, methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" @@ -4162,7 +5812,7 @@ micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@^4.0.2: +micromatch@^4.0.2, micromatch@^4.0.4: version "4.0.4" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== @@ -4197,6 +5847,13 @@ mimic-response@^1.0.0, mimic-response@^1.0.1: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= + dependencies: + dom-walk "^0.1.0" + minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -4296,6 +5953,11 @@ multer@^1.4.2: type-is "^1.6.4" xtend "^4.0.0" +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -4318,6 +5980,11 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= +natural-orderby@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/natural-orderby/-/natural-orderby-2.0.3.tgz#8623bc518ba162f8ff1cdb8941d74deb0fdcc016" + integrity sha512-p7KTHxU0CUrcOXe62Zfrb5Z13nLvPhSWR/so3kFulUQU0sgUll2Z0LwpsLN351eOOD+hRGu/F1g+6xDfPeD++Q== + needle@^2.2.1: version "2.9.1" resolved "https://registry.yarnpkg.com/needle/-/needle-2.9.1.tgz#22d1dffbe3490c2b83e301f7709b6736cd8f2684" @@ -4332,6 +5999,14 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== +netrc-parser@^3.1.6: + version "3.1.6" + resolved "https://registry.yarnpkg.com/netrc-parser/-/netrc-parser-3.1.6.tgz#7243c9ec850b8e805b9bdc7eae7b1450d4a96e72" + integrity sha512-lY+fmkqSwntAAjfP63jB4z5p5WbuZwyMCD3pInT7dpHU/Gc6Vv90SAC6A0aNiqaRGHiuZFBtiwu+pu8W/Eyotw== + dependencies: + debug "^3.1.0" + execa "^0.10.0" + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -4503,7 +6178,7 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" -npm-run-path@^4.0.0: +npm-run-path@^4.0.0, npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== @@ -4559,6 +6234,11 @@ object-keys@^1.0.12, object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== +object-treeify@^1.1.4: + version "1.1.33" + resolved "https://registry.yarnpkg.com/object-treeify/-/object-treeify-1.1.33.tgz#f06fece986830a3cba78ddd32d4c11d1f76cdf40" + integrity sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A== + object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" @@ -4566,7 +6246,7 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" -object.assign@^4.1.2: +object.assign@^4.1.0, object.assign@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== @@ -4618,13 +6298,22 @@ one-time@^1.0.0: dependencies: fn.name "1.x.x" -onetime@^5.1.0: +onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== dependencies: mimic-fn "^2.1.0" +open@^8.0.6: + version "8.4.0" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" + integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + optionator@^0.8.1: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" @@ -4649,6 +6338,21 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.3" +ora@^5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" + integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== + dependencies: + bl "^4.1.0" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.5.0" + is-interactive "^1.0.0" + is-unicode-supported "^0.1.0" + log-symbols "^4.1.0" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" @@ -4808,6 +6512,14 @@ passport@^0.4.0: passport-strategy "1.x.x" pause "0.0.1" +password-prompt@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/password-prompt/-/password-prompt-1.1.2.tgz#85b2f93896c5bd9e9f2d6ff0627fa5af3dc00923" + integrity sha512-bpuBhROdrhuN3E7G/koAju0WjVw9/uQOG5Co5mokNj0MiOSBVZS1JTwM4zl55hu0WFmIEFvO9cU9sJQiBIYeIA== + dependencies: + ansi-escapes "^3.1.0" + cross-spawn "^6.0.5" + path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -4828,7 +6540,7 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.6: +path-parse@^1.0.6, path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== @@ -4838,6 +6550,11 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + pause@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" @@ -4853,6 +6570,18 @@ pg-connection-string@^2.5.0: resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.5.0.tgz#538cadd0f7e603fc09a12590f3b8a452c2c0cf34" integrity sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ== +pg-god@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pg-god/-/pg-god-1.0.11.tgz#5bc73a5ccb0fc5b439177462d9712ef4d1b83c9a" + integrity sha512-bW14qUfEt3jDruac0Pq9O1Pi6vH5cgLKVx3l8IdBrJS7GX0wBS4b6rlfTrU8373MCAXauP6x8VkD0rNE3mTxCw== + dependencies: + "@oclif/command" "^1" + "@oclif/config" "^1" + "@oclif/plugin-help" "^3" + cli-ux "^5.4.9" + pg "^8.3.0" + tslib "^1" + pg-int8@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" @@ -4879,7 +6608,7 @@ pg-types@^2.1.0: postgres-date "~1.0.4" postgres-interval "^1.1.0" -pg@^8.5.1: +pg@^8.3.0, pg@^8.5.1: version "8.7.1" resolved "https://registry.yarnpkg.com/pg/-/pg-8.7.1.tgz#9ea9d1ec225980c36f94e181d009ab9f4ce4c471" integrity sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA== @@ -4990,11 +6719,26 @@ pretty-format@^25.5.0: ansi-styles "^4.0.0" react-is "^16.12.0" +pretty-format@^27.0.0, pretty-format@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.4.2.tgz#e4ce92ad66c3888423d332b40477c87d1dac1fb8" + integrity sha512-p0wNtJ9oLuvgOQDEIZ9zQjZffK7KtyR6Si0jnXULIDwrlNF8Cuir3AZP0hHv0jmKuNN/edOnbMjnzd4uTcmWiw== + dependencies: + "@jest/types" "^27.4.2" + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + progress@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" @@ -5009,7 +6753,7 @@ promise.prototype.finally@^3.1.2: define-properties "^1.1.3" es-abstract "^1.19.1" -prompts@^2.0.1: +prompts@^2.0.1, prompts@^2.4.1: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== @@ -5043,6 +6787,11 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" @@ -5072,6 +6821,16 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + random-bytes@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" @@ -5116,6 +6875,11 @@ react-is@^16.12.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + read-pkg-up@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" @@ -5184,6 +6948,13 @@ realpath-native@^2.0.0: resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-2.0.0.tgz#7377ac429b6e1fd599dc38d08ed942d0d7beb866" integrity sha512-v1SEYUOXXdbBZK8ZuNgO4TBjamPsiSgcFr0aP+tEKpQZK8vooEUqV6nm6Cv502mX4NF2EfsnVqtNAHG+/6Ur1Q== +redeyed@~2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/redeyed/-/redeyed-2.1.1.tgz#8984b5815d99cb220469c99eeeffe38913e6cc0b" + integrity sha1-iYS1gV2ZyyIEacme7v/jiRPmzAs= + dependencies: + esprima "~4.0.0" + redis-commands@1.7.0, redis-commands@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/redis-commands/-/redis-commands-1.7.0.tgz#15a6fea2d58281e27b1cd1acfb4b293e278c3a89" @@ -5216,6 +6987,30 @@ reflect-metadata@^0.1.13: resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== +regenerate-unicode-properties@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz#54d09c7115e1f53dc2314a974b32c1c344efe326" + integrity sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.5: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + +regenerator-transform@^0.14.2: + version "0.14.5" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" + integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== + dependencies: + "@babel/runtime" "^7.8.4" + regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" @@ -5229,6 +7024,18 @@ regexpp@^3.1.0: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== +regexpu-core@^4.7.1: + version "4.8.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.8.0.tgz#e5605ba361b67b1718478501327502f4479a98f0" + integrity sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg== + dependencies: + regenerate "^1.4.2" + regenerate-unicode-properties "^9.0.0" + regjsgen "^0.5.2" + regjsparser "^0.7.0" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.0.0" + registry-auth-token@^4.0.0: version "4.2.1" resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" @@ -5243,11 +7050,28 @@ registry-url@^5.0.0: dependencies: rc "^1.2.8" +regjsgen@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" + integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== + +regjsparser@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.7.0.tgz#a6b667b54c885e18b52554cb4960ef71187e9968" + integrity sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ== + dependencies: + jsesc "~0.5.0" + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= +remove-trailing-slash@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/remove-trailing-slash/-/remove-trailing-slash-0.1.1.tgz#be2285a59f39c74d1bce4f825950061915e3780d" + integrity sha512-o4S4Qh6L2jpnCy83ysZDau+VORNvnFw07CKSAymkd6ICNVEPisMyzlc00KlvvicsxKck94SEwhDnMNdICzO+tA== + repeat-element@^1.1.2: version "1.1.4" resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" @@ -5357,6 +7181,15 @@ resolve@^1.10.0, resolve@^1.17.0: is-core-module "^2.2.0" path-parse "^1.0.6" +resolve@^1.14.2: + version "1.21.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.21.0.tgz#b51adc97f3472e6a5cf4444d34bc9d6b9037591f" + integrity sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA== + dependencies: + is-core-module "^2.8.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + responselike@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" @@ -5364,11 +7197,24 @@ responselike@^1.0.2: dependencies: lowercase-keys "^1.0.0" +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + rimraf@2, rimraf@^2.6.1: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -5388,6 +7234,25 @@ rsvp@^4.8.4: resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +rxjs@^7.2.0: + version "7.5.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.2.tgz#11e4a3a1dfad85dbf7fb6e33cbba17668497490b" + integrity sha512-PwDt186XaL3QN5qXj/H9DGyHhP3/RYYgZZwqBv9Tv8rsAaiwFH1IsJJlcgD37J7UW5a6O67qX0KWKS3/pu0m4w== + dependencies: + tslib "^2.1.0" + safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -5459,7 +7324,12 @@ semver-diff@^3.1.1: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + +semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== @@ -5563,7 +7433,7 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" -signal-exit@^3.0.0, signal-exit@^3.0.2: +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.6" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== @@ -5743,7 +7613,7 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" -stack-trace@0.0.x: +stack-trace@0.0.x, stack-trace@^0.0.10: version "0.0.10" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= @@ -5928,7 +7798,14 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" -supports-hyperlinks@^2.0.0: +supports-color@^8.1.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^2.0.0, supports-hyperlinks@^2.1.0: version "2.2.0" resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== @@ -5936,6 +7813,11 @@ supports-hyperlinks@^2.0.0: has-flag "^4.0.0" supports-color "^7.0.0" +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + symbol-tree@^3.2.2: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" @@ -6006,6 +7888,11 @@ throat@^5.0.0: resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== +through@^2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -6101,7 +7988,12 @@ triple-beam@^1.2.0, triple-beam@^1.3.0: resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== -tslib@^2.0.3: +tslib@^1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== @@ -6209,6 +8101,29 @@ undefsafe@^2.0.5: resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" + integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" + integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== + union-value@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" @@ -6226,6 +8141,16 @@ unique-string@^2.0.0: dependencies: crypto-random-string "^2.0.0" +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -6278,6 +8203,14 @@ url-parse-lax@^3.0.0: dependencies: prepend-http "^2.0.0" +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" @@ -6309,7 +8242,7 @@ uuid@^3.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^8.3.0, uuid@^8.3.1: +uuid@^8.3.0, uuid@^8.3.1, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== @@ -6378,6 +8311,13 @@ walker@^1.0.7, walker@~1.0.5: dependencies: makeerror "1.0.12" +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" + integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= + dependencies: + defaults "^1.0.3" + webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" @@ -6456,6 +8396,15 @@ winston-transport@^4.4.0: readable-stream "^2.3.7" triple-beam "^1.2.0" +winston-transport@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.4.2.tgz#554efe3fce229d046df006e0e3c411d240652e51" + integrity sha512-9jmhltAr5ygt5usgUTQbEiw/7RYXpyUbEAFRCSicIacpUzPkrnQsQZSPGEI12aLK9Jth4zNcYJx3Cvznwrl8pw== + dependencies: + logform "^2.3.2" + readable-stream "^3.4.0" + triple-beam "^1.2.0" + winston@^3.2.1: version "3.3.3" resolved "https://registry.yarnpkg.com/winston/-/winston-3.3.3.tgz#ae6172042cafb29786afa3d09c8ff833ab7c9170" @@ -6471,6 +8420,21 @@ winston@^3.2.1: triple-beam "^1.3.0" winston-transport "^4.4.0" +winston@^3.3.3: + version "3.4.0" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.4.0.tgz#7080f24b02a0684f8a37f9d5c6afb1ac23e95b84" + integrity sha512-FqilVj+5HKwCfIHQzMxrrd5tBIH10JTS3koFGbLVWBODjiIYq7zir08rFyBT4rrTYG/eaTqDcfSIbcjSM78YSw== + dependencies: + "@dabh/diagnostics" "^2.0.2" + async "^3.2.3" + is-stream "^2.0.0" + logform "^2.3.2" + one-time "^1.0.0" + readable-stream "^3.4.0" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.4.2" + word-wrap@^1.2.3, word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"