├── .babelrc.js ├── .dockerignore ├── .env.template ├── .github └── workflows │ └── npm-publish.yml ├── .gitignore ├── .npmignore ├── README.md ├── data └── seed.json ├── docker-compose.yml ├── index.js ├── package-lock.json ├── package.json ├── src ├── loaders │ └── index.ts ├── services │ ├── README.md │ ├── magento-category.ts │ ├── magento-client.ts │ └── magento-product.ts └── strategies │ └── import.ts ├── tsconfig.json └── yarn.lock /.babelrc.js: -------------------------------------------------------------------------------- 1 | let ignore = [`**/dist`]; 2 | 3 | // Jest needs to compile this code, but generally we don't want this copied 4 | // to output folders 5 | if (process.env.NODE_ENV !== `test`) { 6 | ignore.push(`**/__tests__`); 7 | } 8 | 9 | module.exports = { 10 | presets: [["babel-preset-medusa-package"], ["@babel/preset-typescript", { 11 | allowDeclareFields: true 12 | }]], 13 | ignore, 14 | }; 15 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | 4 | npm-debug.log 5 | -------------------------------------------------------------------------------- /.env.template: -------------------------------------------------------------------------------- 1 | JWT_SECRET=something 2 | COOKIE_SECRET=something 3 | STRIPE_API_KEY= 4 | STRIPE_WEBHOOK_SECRET= 5 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created 2 | # For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages 3 | 4 | name: Node.js Package 5 | 6 | on: 7 | release: 8 | types: [created] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | - uses: actions/setup-node@v3 16 | with: 17 | node-version: 16 18 | - run: npm ci 19 | - run: npm test 20 | 21 | publish-npm: 22 | needs: build 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v3 26 | - uses: actions/setup-node@v3 27 | with: 28 | node-version: 16 29 | registry-url: https://registry.npmjs.org/ 30 | - run: npm ci 31 | - run: npm publish 32 | env: 33 | NODE_AUTH_TOKEN: ${{secrets.npm_token}} 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /dist 2 | .env 3 | .DS_Store 4 | /uploads 5 | /node_modules 6 | yarn-error.log 7 | /.idea 8 | 9 | medusa-config.js 10 | Dockerfile 11 | medusa-db.sql 12 | develop.sh 13 | /loaders 14 | /services 15 | /strategies 16 | /data -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /lib 2 | node_modules 3 | .DS_store 4 | .env* 5 | /*.js 6 | !index.js 7 | yarn.lock 8 | src 9 | .gitignore 10 | .eslintrc 11 | .babelrc 12 | .prettierrc 13 | 14 | #These are files that are included in a 15 | #Medusa project and can be removed from a 16 | #plugin project 17 | medusa-config.js 18 | Dockerfile 19 | medusa-db.sql 20 | develop.sh -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | Medusa 4 | 5 |

6 |

7 | Magento Source Plugin for Medusa 8 |

9 |

10 | A Medusa plugin that imports categories and products from Magento into Medusa. 11 |

12 | 13 | ## Description 14 | 15 | This plugin imports Magento categories and products into Medusa. It creates categories and products that don't exist, and updates those that have been imported previously. 16 | 17 | ### Limitations 18 | 19 | Magento has 6 product types. As some of those types don't exist in Medusa, only the Configurable and Simple products can be imported. 20 | 21 | ## Prerequisites 22 | 23 | ### Medusa Setup 24 | 25 | You must have a [Medusa server installed](https://docs.medusajs.com/quickstart/quick-start) before installing this plugin. 26 | 27 | Furthermore, the Medusa server should have [PostgreSQL](https://docs.medusajs.com/tutorial/set-up-your-development-environment#postgresql) and [Redis](https://docs.medusajs.com/tutorial/set-up-your-development-environment#redis) installed and configured on your Medusa server. 28 | 29 | ### Magento Setup 30 | 31 | On your Magento admin, go to System -> Integrations -> Add New Integrations. 32 | 33 | You need to give the integration the access to the following resources: 34 | 35 | - Catalog (with its child resources). 36 | - Stores -> Settings (with its child resources). 37 | - Stores -> Attributes (with its child resources). 38 | 39 | After creating the integration, activate it from the Integrations listing page. Once you activate it, you'll receive four keys: Consumer Key, Consumer Secret, Access Token, and Access Token Secret. Copy them as you'll need them for the plugin's options. 40 | 41 | ## Installing Plugin 42 | 43 | To install the plugin run the following command on your Medusa server: 44 | 45 | ```bash 46 | npm install medusa-source-magento 47 | ``` 48 | 49 | ## Plugin Configurations 50 | 51 | Add the plugin and its options into the `plugins` array in `medusa-config.js`: 52 | 53 | ```js 54 | const plugins = [ 55 | //... 56 | { 57 | resolve: `medusa-source-magento`, 58 | //if your plugin has configurations 59 | options: { 60 | magento_url: '', 61 | consumer_key: '', 62 | consumer_secret: '', 63 | access_token: '', 64 | access_token_secret: '', 65 | image_prefix: '' // optional 66 | }, 67 | }, 68 | ]; 69 | ``` 70 | 71 | ### Options 72 | 73 | | Name | Description | Required | Default Value| 74 | -------|-------------|----------|--------------| 75 | | `magento_url` | The URL of your Medusa server. It shouldn't end with a backslash. | true | | 76 | | `consumer_key` | The Consumer Key of the integration. | true | | 77 | | `consumer_secret` | The Consumer Secret of the integration. | true | | 78 | | `access_token` | The Access Token of the integration. | true | | 79 | | `access_token_secret` | The Access Token Secret of the integration | true | | 80 | | `image_prefix` | The URL prefix of media files. This is necessary if you don't use Magento's default storage for product images (for example, if you use S3) | false | The URL will be retrieved from Magento. | 81 | 82 | ## Use the Plugin 83 | 84 | ### Server Startup 85 | 86 | To use the plugin, just start the Medusa server: 87 | 88 | ```bash 89 | npm start 90 | ``` 91 | 92 | The import process will run in the background of the server. Based on how many products you have, it can take some time the first time running it. 93 | 94 | ### As a Batch Job 95 | 96 | You can trigger the import by creating a new batch job using the Create Batch Job API endpoint. You can pass the following in the payload: 97 | 98 | ```json 99 | { 100 | "type": "import-magento", 101 | "context": { }, 102 | "dry_run": false 103 | } 104 | ``` 105 | 106 | This will trigger the import process. -------------------------------------------------------------------------------- /data/seed.json: -------------------------------------------------------------------------------- 1 | { 2 | "store": { 3 | "currencies": ["eur", "usd"] 4 | }, 5 | "users": [ 6 | { 7 | "email": "admin@medusa-test.com", 8 | "password": "supersecret" 9 | } 10 | ], 11 | "regions": [ 12 | { 13 | "id": "test-region-eu", 14 | "name": "EU", 15 | "currency_code": "eur", 16 | "tax_rate": 0, 17 | "payment_providers": ["manual"], 18 | "fulfillment_providers": ["manual"], 19 | "countries": ["gb", "de", "dk", "se", "fr", "es", "it"] 20 | }, 21 | { 22 | "id": "test-region-na", 23 | "name": "NA", 24 | "currency_code": "usd", 25 | "tax_rate": 0, 26 | "payment_providers": ["manual"], 27 | "fulfillment_providers": ["manual"], 28 | "countries": ["us", "ca"] 29 | } 30 | ], 31 | "shipping_options": [ 32 | { 33 | "name": "PostFake Standard", 34 | "region_id": "test-region-eu", 35 | "provider_id": "manual", 36 | "data": { 37 | "id": "manual-fulfillment" 38 | }, 39 | "price_type": "flat_rate", 40 | "amount": 1000 41 | }, 42 | { 43 | "name": "PostFake Express", 44 | "region_id": "test-region-eu", 45 | "provider_id": "manual", 46 | "data": { 47 | "id": "manual-fulfillment" 48 | }, 49 | "price_type": "flat_rate", 50 | "amount": 1500 51 | }, 52 | { 53 | "name": "PostFake Return", 54 | "region_id": "test-region-eu", 55 | "provider_id": "manual", 56 | "data": { 57 | "id": "manual-fulfillment" 58 | }, 59 | "price_type": "flat_rate", 60 | "is_return": true, 61 | "amount": 1000 62 | }, 63 | { 64 | "name": "I want to return it myself", 65 | "region_id": "test-region-eu", 66 | "provider_id": "manual", 67 | "data": { 68 | "id": "manual-fulfillment" 69 | }, 70 | "price_type": "flat_rate", 71 | "is_return": true, 72 | "amount": 0 73 | }, 74 | { 75 | "name": "FakeEx Standard", 76 | "region_id": "test-region-na", 77 | "provider_id": "manual", 78 | "data": { 79 | "id": "manual-fulfillment" 80 | }, 81 | "price_type": "flat_rate", 82 | "amount": 800 83 | }, 84 | { 85 | "name": "FakeEx Express", 86 | "region_id": "test-region-na", 87 | "provider_id": "manual", 88 | "data": { 89 | "id": "manual-fulfillment" 90 | }, 91 | "price_type": "flat_rate", 92 | "amount": 1200 93 | }, 94 | { 95 | "name": "FakeEx Return", 96 | "region_id": "test-region-na", 97 | "provider_id": "manual", 98 | "data": { 99 | "id": "manual-fulfillment" 100 | }, 101 | "price_type": "flat_rate", 102 | "is_return": true, 103 | "amount": 800 104 | }, 105 | { 106 | "name": "I want to return it myself", 107 | "region_id": "test-region-na", 108 | "provider_id": "manual", 109 | "data": { 110 | "id": "manual-fulfillment" 111 | }, 112 | "price_type": "flat_rate", 113 | "is_return": true, 114 | "amount": 0 115 | } 116 | ], 117 | "products": [ 118 | { 119 | "title": "Medusa T-Shirt", 120 | "subtitle": null, 121 | "description": "Reimagine the feeling of a classic T-shirt. With our cotton T-shirts, everyday essentials no longer have to be ordinary.", 122 | "handle": "t-shirt", 123 | "is_giftcard": false, 124 | "weight": 400, 125 | "images": [ 126 | "https://medusa-public-images.s3.eu-west-1.amazonaws.com/tee-black-front.png", 127 | "https://medusa-public-images.s3.eu-west-1.amazonaws.com/tee-black-back.png", 128 | "https://medusa-public-images.s3.eu-west-1.amazonaws.com/tee-white-front.png", 129 | "https://medusa-public-images.s3.eu-west-1.amazonaws.com/tee-white-back.png" 130 | ], 131 | "options": [ 132 | { 133 | "title": "Size", 134 | "values": ["S", "M", "L", "XL"] 135 | }, 136 | { 137 | "title": "Color", 138 | "values": ["Black", "White"] 139 | } 140 | ], 141 | "variants": [ 142 | { 143 | "title": "S / Black", 144 | "prices": [ 145 | { 146 | "currency_code": "eur", 147 | "amount": 1950 148 | }, 149 | { 150 | "currency_code": "usd", 151 | "amount": 2200 152 | } 153 | ], 154 | "options": [ 155 | { 156 | "value": "S" 157 | }, 158 | { 159 | "value": "Black" 160 | } 161 | ], 162 | "inventory_quantity": 100, 163 | "manage_inventory": true 164 | }, 165 | { 166 | "title": "S / White", 167 | "prices": [ 168 | { 169 | "currency_code": "eur", 170 | "amount": 1950 171 | }, 172 | { 173 | "currency_code": "usd", 174 | "amount": 2200 175 | } 176 | ], 177 | "options": [ 178 | { 179 | "value": "S" 180 | }, 181 | { 182 | "value": "White" 183 | } 184 | ], 185 | "inventory_quantity": 100, 186 | "manage_inventory": true 187 | }, 188 | { 189 | "title": "M / Black", 190 | "prices": [ 191 | { 192 | "currency_code": "eur", 193 | "amount": 1950 194 | }, 195 | { 196 | "currency_code": "usd", 197 | "amount": 2200 198 | } 199 | ], 200 | "options": [ 201 | { 202 | "value": "M" 203 | }, 204 | { 205 | "value": "Black" 206 | } 207 | ], 208 | "inventory_quantity": 100, 209 | "manage_inventory": true 210 | }, 211 | { 212 | "title": "M / White", 213 | "prices": [ 214 | { 215 | "currency_code": "eur", 216 | "amount": 1950 217 | }, 218 | { 219 | "currency_code": "usd", 220 | "amount": 2200 221 | } 222 | ], 223 | "options": [ 224 | { 225 | "value": "M" 226 | }, 227 | { 228 | "value": "White" 229 | } 230 | ], 231 | "inventory_quantity": 100, 232 | "manage_inventory": true 233 | }, 234 | { 235 | "title": "L / Black", 236 | "prices": [ 237 | { 238 | "currency_code": "eur", 239 | "amount": 1950 240 | }, 241 | { 242 | "currency_code": "usd", 243 | "amount": 2200 244 | } 245 | ], 246 | "options": [ 247 | { 248 | "value": "L" 249 | }, 250 | { 251 | "value": "Black" 252 | } 253 | ], 254 | "inventory_quantity": 100, 255 | "manage_inventory": true 256 | }, 257 | { 258 | "title": "L / White", 259 | "prices": [ 260 | { 261 | "currency_code": "eur", 262 | "amount": 1950 263 | }, 264 | { 265 | "currency_code": "usd", 266 | "amount": 2200 267 | } 268 | ], 269 | "options": [ 270 | { 271 | "value": "L" 272 | }, 273 | { 274 | "value": "White" 275 | } 276 | ], 277 | "inventory_quantity": 100, 278 | "manage_inventory": true 279 | }, 280 | { 281 | "title": "XL / Black", 282 | "prices": [ 283 | { 284 | "currency_code": "eur", 285 | "amount": 1950 286 | }, 287 | { 288 | "currency_code": "usd", 289 | "amount": 2200 290 | } 291 | ], 292 | "options": [ 293 | { 294 | "value": "XL" 295 | }, 296 | { 297 | "value": "Black" 298 | } 299 | ], 300 | "inventory_quantity": 100, 301 | "manage_inventory": true 302 | }, 303 | { 304 | "title": "XL / White", 305 | "prices": [ 306 | { 307 | "currency_code": "eur", 308 | "amount": 1950 309 | }, 310 | { 311 | "currency_code": "usd", 312 | "amount": 2200 313 | } 314 | ], 315 | "options": [ 316 | { 317 | "value": "XL" 318 | }, 319 | { 320 | "value": "White" 321 | } 322 | ], 323 | "inventory_quantity": 100, 324 | "manage_inventory": true 325 | } 326 | ] 327 | }, 328 | { 329 | "title": "Medusa Sweatshirt", 330 | "subtitle": null, 331 | "description": "Reimagine the feeling of a classic sweatshirt. With our cotton sweatshirt, everyday essentials no longer have to be ordinary.", 332 | "handle": "sweatshirt", 333 | "is_giftcard": false, 334 | "weight": 400, 335 | "images": [ 336 | "https://medusa-public-images.s3.eu-west-1.amazonaws.com/sweatshirt-vintage-front.png", 337 | "https://medusa-public-images.s3.eu-west-1.amazonaws.com/sweatshirt-vintage-back.png" 338 | ], 339 | "options": [ 340 | { 341 | "title": "Size", 342 | "values": ["S", "M", "L", "XL"] 343 | } 344 | ], 345 | "variants": [ 346 | { 347 | "title": "S", 348 | "prices": [ 349 | { 350 | "currency_code": "eur", 351 | "amount": 2950 352 | }, 353 | { 354 | "currency_code": "usd", 355 | "amount": 3350 356 | } 357 | ], 358 | "options": [ 359 | { 360 | "value": "S" 361 | } 362 | ], 363 | "inventory_quantity": 100, 364 | "manage_inventory": true 365 | }, 366 | { 367 | "title": "M", 368 | "prices": [ 369 | { 370 | "currency_code": "eur", 371 | "amount": 2950 372 | }, 373 | { 374 | "currency_code": "usd", 375 | "amount": 3350 376 | } 377 | ], 378 | "options": [ 379 | { 380 | "value": "M" 381 | } 382 | ], 383 | "inventory_quantity": 100, 384 | "manage_inventory": true 385 | }, 386 | { 387 | "title": "L", 388 | "prices": [ 389 | { 390 | "currency_code": "eur", 391 | "amount": 2950 392 | }, 393 | { 394 | "currency_code": "usd", 395 | "amount": 3350 396 | } 397 | ], 398 | "options": [ 399 | { 400 | "value": "L" 401 | } 402 | ], 403 | "inventory_quantity": 100, 404 | "manage_inventory": true 405 | }, 406 | { 407 | "title": "XL", 408 | "prices": [ 409 | { 410 | "currency_code": "eur", 411 | "amount": 2950 412 | }, 413 | { 414 | "currency_code": "usd", 415 | "amount": 3350 416 | } 417 | ], 418 | "options": [ 419 | { 420 | "value": "XL" 421 | } 422 | ], 423 | "inventory_quantity": 100, 424 | "manage_inventory": true 425 | } 426 | ] 427 | }, 428 | { 429 | "title": "Medusa Sweatpants", 430 | "subtitle": null, 431 | "description": "Reimagine the feeling of classic sweatpants. With our cotton sweatpants, everyday essentials no longer have to be ordinary.", 432 | "handle": "sweatpants", 433 | "is_giftcard": false, 434 | "weight": 400, 435 | "images": [ 436 | "https://medusa-public-images.s3.eu-west-1.amazonaws.com/sweatpants-gray-front.png", 437 | "https://medusa-public-images.s3.eu-west-1.amazonaws.com/sweatpants-gray-back.png" 438 | ], 439 | "options": [ 440 | { 441 | "title": "Size", 442 | "values": ["S", "M", "L", "XL"] 443 | } 444 | ], 445 | "variants": [ 446 | { 447 | "title": "S", 448 | "prices": [ 449 | { 450 | "currency_code": "eur", 451 | "amount": 2950 452 | }, 453 | { 454 | "currency_code": "usd", 455 | "amount": 3350 456 | } 457 | ], 458 | "options": [ 459 | { 460 | "value": "S" 461 | } 462 | ], 463 | "inventory_quantity": 100, 464 | "manage_inventory": true 465 | }, 466 | { 467 | "title": "M", 468 | "prices": [ 469 | { 470 | "currency_code": "eur", 471 | "amount": 2950 472 | }, 473 | { 474 | "currency_code": "usd", 475 | "amount": 3350 476 | } 477 | ], 478 | "options": [ 479 | { 480 | "value": "M" 481 | } 482 | ], 483 | "inventory_quantity": 100, 484 | "manage_inventory": true 485 | }, 486 | { 487 | "title": "L", 488 | "prices": [ 489 | { 490 | "currency_code": "eur", 491 | "amount": 2950 492 | }, 493 | { 494 | "currency_code": "usd", 495 | "amount": 3350 496 | } 497 | ], 498 | "options": [ 499 | { 500 | "value": "L" 501 | } 502 | ], 503 | "inventory_quantity": 100, 504 | "manage_inventory": true 505 | }, 506 | { 507 | "title": "XL", 508 | "prices": [ 509 | { 510 | "currency_code": "eur", 511 | "amount": 2950 512 | }, 513 | { 514 | "currency_code": "usd", 515 | "amount": 3350 516 | } 517 | ], 518 | "options": [ 519 | { 520 | "value": "XL" 521 | } 522 | ], 523 | "inventory_quantity": 100, 524 | "manage_inventory": true 525 | } 526 | ] 527 | }, 528 | { 529 | "title": "Medusa Shorts", 530 | "subtitle": null, 531 | "description": "Reimagine the feeling of classic shorts. With our cotton shorts, everyday essentials no longer have to be ordinary.", 532 | "handle": "shorts", 533 | "is_giftcard": false, 534 | "weight": 400, 535 | "images": [ 536 | "https://medusa-public-images.s3.eu-west-1.amazonaws.com/shorts-vintage-front.png", 537 | "https://medusa-public-images.s3.eu-west-1.amazonaws.com/shorts-vintage-back.png" 538 | ], 539 | "options": [ 540 | { 541 | "title": "Size", 542 | "values": ["S", "M", "L", "XL"] 543 | } 544 | ], 545 | "variants": [ 546 | { 547 | "title": "S", 548 | "prices": [ 549 | { 550 | "currency_code": "eur", 551 | "amount": 2500 552 | }, 553 | { 554 | "currency_code": "usd", 555 | "amount": 2850 556 | } 557 | ], 558 | "options": [ 559 | { 560 | "value": "S" 561 | } 562 | ], 563 | "inventory_quantity": 100, 564 | "manage_inventory": true 565 | }, 566 | { 567 | "title": "M", 568 | "prices": [ 569 | { 570 | "currency_code": "eur", 571 | "amount": 2500 572 | }, 573 | { 574 | "currency_code": "usd", 575 | "amount": 2850 576 | } 577 | ], 578 | "options": [ 579 | { 580 | "value": "M" 581 | } 582 | ], 583 | "inventory_quantity": 100, 584 | "manage_inventory": true 585 | }, 586 | { 587 | "title": "L", 588 | "prices": [ 589 | { 590 | "currency_code": "eur", 591 | "amount": 2500 592 | }, 593 | { 594 | "currency_code": "usd", 595 | "amount": 2850 596 | } 597 | ], 598 | "options": [ 599 | { 600 | "value": "L" 601 | } 602 | ], 603 | "inventory_quantity": 100, 604 | "manage_inventory": true 605 | }, 606 | { 607 | "title": "XL", 608 | "prices": [ 609 | { 610 | "currency_code": "eur", 611 | "amount": 2500 612 | }, 613 | { 614 | "currency_code": "usd", 615 | "amount": 2850 616 | } 617 | ], 618 | "options": [ 619 | { 620 | "value": "XL" 621 | } 622 | ], 623 | "inventory_quantity": 100, 624 | "manage_inventory": true 625 | } 626 | ] 627 | }, 628 | { 629 | "title": "Medusa Hoodie", 630 | "subtitle": null, 631 | "description": "Reimagine the feeling of a classic hoodie. With our cotton hoodie, everyday essentials no longer have to be ordinary.", 632 | "handle": "hoodie", 633 | "is_giftcard": false, 634 | "weight": 400, 635 | "images": [ 636 | "https://medusa-public-images.s3.eu-west-1.amazonaws.com/black_hoodie_front.png", 637 | "https://medusa-public-images.s3.eu-west-1.amazonaws.com/black_hoodie_back.png" 638 | ], 639 | "options": [ 640 | { 641 | "title": "Size", 642 | "values": ["S", "M", "L", "XL"] 643 | } 644 | ], 645 | "variants": [ 646 | { 647 | "title": "S", 648 | "prices": [ 649 | { 650 | "currency_code": "eur", 651 | "amount": 3650 652 | }, 653 | { 654 | "currency_code": "usd", 655 | "amount": 4150 656 | } 657 | ], 658 | "options": [ 659 | { 660 | "value": "S" 661 | } 662 | ], 663 | "inventory_quantity": 100, 664 | "manage_inventory": true 665 | }, 666 | { 667 | "title": "M", 668 | "prices": [ 669 | { 670 | "currency_code": "eur", 671 | "amount": 3650 672 | }, 673 | { 674 | "currency_code": "usd", 675 | "amount": 4150 676 | } 677 | ], 678 | "options": [ 679 | { 680 | "value": "M" 681 | } 682 | ], 683 | "inventory_quantity": 100, 684 | "manage_inventory": true 685 | }, 686 | { 687 | "title": "L", 688 | "prices": [ 689 | { 690 | "currency_code": "eur", 691 | "amount": 3650 692 | }, 693 | { 694 | "currency_code": "usd", 695 | "amount": 4150 696 | } 697 | ], 698 | "options": [ 699 | { 700 | "value": "L" 701 | } 702 | ], 703 | "inventory_quantity": 100, 704 | "manage_inventory": true 705 | }, 706 | { 707 | "title": "XL", 708 | "prices": [ 709 | { 710 | "currency_code": "eur", 711 | "amount": 3650 712 | }, 713 | { 714 | "currency_code": "usd", 715 | "amount": 4150 716 | } 717 | ], 718 | "options": [ 719 | { 720 | "value": "XL" 721 | } 722 | ], 723 | "inventory_quantity": 100, 724 | "manage_inventory": true 725 | } 726 | ] 727 | }, 728 | { 729 | "title": "Medusa Longsleeve", 730 | "subtitle": null, 731 | "description": "Reimagine the feeling of a classic longsleeve. With our cotton longsleeve, everyday essentials no longer have to be ordinary.", 732 | "handle": "longsleeve", 733 | "is_giftcard": false, 734 | "weight": 400, 735 | "images": [ 736 | "https://medusa-public-images.s3.eu-west-1.amazonaws.com/ls-black-front.png", 737 | "https://medusa-public-images.s3.eu-west-1.amazonaws.com/ls-black-back.png" 738 | ], 739 | "options": [ 740 | { 741 | "title": "Size", 742 | "values": ["S", "M", "L", "XL"] 743 | } 744 | ], 745 | "variants": [ 746 | { 747 | "title": "S", 748 | "prices": [ 749 | { 750 | "currency_code": "eur", 751 | "amount": 3650 752 | }, 753 | { 754 | "currency_code": "usd", 755 | "amount": 4150 756 | } 757 | ], 758 | "options": [ 759 | { 760 | "value": "S" 761 | } 762 | ], 763 | "inventory_quantity": 100, 764 | "manage_inventory": true 765 | }, 766 | { 767 | "title": "M", 768 | "prices": [ 769 | { 770 | "currency_code": "eur", 771 | "amount": 3650 772 | }, 773 | { 774 | "currency_code": "usd", 775 | "amount": 4150 776 | } 777 | ], 778 | "options": [ 779 | { 780 | "value": "M" 781 | } 782 | ], 783 | "inventory_quantity": 100, 784 | "manage_inventory": true 785 | }, 786 | { 787 | "title": "L", 788 | "prices": [ 789 | { 790 | "currency_code": "eur", 791 | "amount": 3650 792 | }, 793 | { 794 | "currency_code": "usd", 795 | "amount": 4150 796 | } 797 | ], 798 | "options": [ 799 | { 800 | "value": "L" 801 | } 802 | ], 803 | "inventory_quantity": 100, 804 | "manage_inventory": true 805 | }, 806 | { 807 | "title": "XL", 808 | "prices": [ 809 | { 810 | "currency_code": "eur", 811 | "amount": 3650 812 | }, 813 | { 814 | "currency_code": "usd", 815 | "amount": 4150 816 | } 817 | ], 818 | "options": [ 819 | { 820 | "value": "XL" 821 | } 822 | ], 823 | "inventory_quantity": 100, 824 | "manage_inventory": true 825 | } 826 | ] 827 | }, 828 | { 829 | "title": "Medusa Coffee Mug", 830 | "subtitle": null, 831 | "description": "Every programmer's best friend.", 832 | "handle": "coffee-mug", 833 | "is_giftcard": false, 834 | "weight": 400, 835 | "images": [ 836 | "https://medusa-public-images.s3.eu-west-1.amazonaws.com/coffee-mug.png" 837 | ], 838 | "options": [ 839 | { 840 | "title": "Size", 841 | "values": ["One Size"] 842 | } 843 | ], 844 | "variants": [ 845 | { 846 | "title": "One Size", 847 | "prices": [ 848 | { 849 | "currency_code": "eur", 850 | "amount": 1000 851 | }, 852 | { 853 | "currency_code": "usd", 854 | "amount": 1200 855 | } 856 | ], 857 | "options": [ 858 | { 859 | "value": "One Size" 860 | } 861 | ], 862 | "inventory_quantity": 100, 863 | "manage_inventory": true 864 | } 865 | ] 866 | } 867 | ] 868 | } 869 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | services: 3 | backend: 4 | build: 5 | context: . 6 | dockerfile: Dockerfile 7 | image: backend:starter 8 | container_name: medusa-server-default 9 | depends_on: 10 | - postgres 11 | - redis 12 | environment: 13 | DATABASE_URL: postgres://postgres:postgres@postgres:5432/medusa-docker 14 | REDIS_URL: redis://redis 15 | NODE_ENV: development 16 | JWT_SECRET: something 17 | COOKIE_SECRET: something 18 | PORT: 9000 19 | ports: 20 | - "9000:9000" 21 | volumes: 22 | - .:/app/medusa 23 | - node_modules:/app/medusa/node_modules 24 | 25 | postgres: 26 | image: postgres:10.4 27 | ports: 28 | - "5432:5432" 29 | environment: 30 | POSTGRES_USER: postgres 31 | POSTGRES_PASSWORD: postgres 32 | POSTGRES_DB: medusa-docker 33 | 34 | redis: 35 | image: redis 36 | expose: 37 | - 6379 38 | 39 | volumes: 40 | node_modules: 41 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // noop -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "medusa-source-magento", 3 | "version": "0.0.9", 4 | "description": "Source plugins that allows users to import data from a Magento store to Medusa", 5 | "author": "Shahed Nasser ", 6 | "license": "MIT", 7 | "main": "index.js", 8 | "scripts": { 9 | "seed": "medusa seed -f ./data/seed.json", 10 | "build": "babel src --out-dir . --ignore **/__tests__ --extensions \".ts,.js\"", 11 | "start": "medusa develop", 12 | "watch": "babel -w src --out-dir . --ignore **/__tests__ --extensions \".ts,.js\"", 13 | "prepare": "cross-env NODE_ENV=production npm run build" 14 | }, 15 | "peerDependencies": { 16 | "@medusajs/medusa": "^1.5.0", 17 | "axios": "^1.1.2", 18 | "medusa-interfaces": "^1.3.0", 19 | "typeorm": "^0.2.36", 20 | "medusa-core-utils": "^1.1.33" 21 | }, 22 | "devDependencies": { 23 | "@babel/cli": "^7.14.3", 24 | "@babel/core": "^7.14.3", 25 | "@babel/preset-typescript": "^7.14.5", 26 | "babel-preset-medusa-package": "^1.1.19", 27 | "cross-env": "^7.0.3" 28 | }, 29 | "repository": "https://github.com/shahednasser/medusa-source-magento", 30 | "keywords": [ 31 | "medusa-plugin", 32 | "medusa-plugin-source" 33 | ], 34 | "dependencies": { 35 | "axios-oauth-1.0a": "^0.3.6" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/loaders/index.ts: -------------------------------------------------------------------------------- 1 | import { BatchJobService } from '@medusajs/medusa' 2 | 3 | export default async (container, options) => { 4 | try { 5 | const batchJobService: BatchJobService = container.resolve("batchJobService") 6 | console.log("Creating batch job to import magento products...") 7 | await batchJobService.create({ 8 | type: 'import-magento', 9 | context: { 10 | options 11 | }, 12 | dry_run: false, 13 | created_by: null 14 | }) 15 | } catch (err) { 16 | console.log(err) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/services/README.md: -------------------------------------------------------------------------------- 1 | # Custom services 2 | 3 | You may define custom services that will be registered on the global container by creating files in the `/services` directory that export an instance of `BaseService`. 4 | 5 | ```js 6 | // my.js 7 | 8 | import { BaseService } from "medusa-interfaces"; 9 | 10 | class MyService extends BaseService { 11 | constructor({ productService }) { 12 | super(); 13 | 14 | this.productService_ = productService 15 | } 16 | 17 | async getProductMessage() { 18 | const [product] = await this.productService_.list({}, { take: 1 }) 19 | 20 | return `Welcome to ${product.title}!` 21 | } 22 | } 23 | 24 | export default MyService; 25 | ``` 26 | 27 | The first argument to the `constructor` is the global giving you access to easy dependency injection. The container holds all registered services from the core, installed plugins and from other files in the `/services` directory. The registration name is a camelCased version of the file name with the type appended i.e.: `my.js` is registered as `myService`, `custom-thing.js` is registered as `customThingService`. 28 | 29 | You may use the services you define here in custom endpoints by resolving the services defined. 30 | 31 | ```js 32 | import { Router } from "express" 33 | 34 | export default () => { 35 | const router = Router() 36 | 37 | router.get("/hello-product", async (req, res) => { 38 | const myService = req.scope.resolve("myService") 39 | 40 | res.json({ 41 | message: await myService.getProductMessage() 42 | }) 43 | }) 44 | 45 | return router; 46 | } 47 | ``` 48 | -------------------------------------------------------------------------------- /src/services/magento-category.ts: -------------------------------------------------------------------------------- 1 | import MagentoClientService, { PluginOptions } from './magento-client'; 2 | import { ProductCollection, ProductCollectionService, TransactionBaseService } from '@medusajs/medusa'; 3 | 4 | import { EntityManager } from 'typeorm'; 5 | 6 | type InjectedDependencies = { 7 | magentoClientService: MagentoClientService; 8 | productCollectionService: ProductCollectionService; 9 | manager: EntityManager; 10 | } 11 | 12 | class MagentoCategoryService extends TransactionBaseService { 13 | declare protected manager_: EntityManager; 14 | declare protected transactionManager_: EntityManager; 15 | protected magentoClientService_: MagentoClientService; 16 | protected productCollectionService_: ProductCollectionService; 17 | 18 | constructor(container: InjectedDependencies, options: PluginOptions) { 19 | super(container); 20 | 21 | this.manager_ = container.manager; 22 | this.magentoClientService_ = container.magentoClientService; 23 | this.productCollectionService_ = container.productCollectionService; 24 | } 25 | 26 | async create (category: any): Promise { 27 | return this.atomicPhase_(async (manager) => { 28 | //check if a collection exists for the category 29 | const existingCollection = await this.productCollectionService_ 30 | .withTransaction(manager) 31 | .retrieveByHandle(this.getHandle(category)) 32 | .catch(() => undefined); 33 | 34 | if (existingCollection) { 35 | return this.update(category, existingCollection) 36 | } 37 | 38 | //create collection 39 | const collectionData = this.normalizeCollection(category); 40 | 41 | await this.productCollectionService_ 42 | .withTransaction(manager) 43 | .create(collectionData) 44 | }) 45 | } 46 | 47 | async update (category: any, existingCollection: ProductCollection): Promise { 48 | return this.atomicPhase_(async (manager) => { 49 | const collectionData = this.normalizeCollection(category); 50 | 51 | const update = {} 52 | 53 | for (const key of Object.keys(collectionData)) { 54 | if (collectionData[key] !== existingCollection[key]) { 55 | update[key] = collectionData[key] 56 | } 57 | } 58 | 59 | if (Object.values(update).length) { 60 | await this.productCollectionService_ 61 | .withTransaction(manager) 62 | .update(existingCollection.id, update) 63 | } 64 | }) 65 | } 66 | 67 | normalizeCollection (category: any): any { 68 | return { 69 | title: category.name, 70 | handle: category.custom_attributes.find((attribute) => attribute.attribute_code === 'url_key')?.value, 71 | metadata: { 72 | magento_id: category.id 73 | } 74 | } 75 | } 76 | 77 | getHandle(category: any): string { 78 | return category.custom_attributes.find((attribute) => attribute.attribute_code === 'url_key')?.value || '' 79 | } 80 | } 81 | 82 | export default MagentoCategoryService; -------------------------------------------------------------------------------- /src/services/magento-client.ts: -------------------------------------------------------------------------------- 1 | import axios, { AxiosInstance, AxiosResponse, Method } from 'axios'; 2 | 3 | import { EntityManager } from 'typeorm'; 4 | import { Logger } from '@medusajs/medusa/dist/types/global'; 5 | import { MedusaError } from 'medusa-core-utils'; 6 | import { TransactionBaseService } from '@medusajs/medusa'; 7 | import addOAuthInterceptor from 'axios-oauth-1.0a'; 8 | 9 | export type PluginOptions = { 10 | magento_url: string; 11 | consumer_key: string; 12 | consumer_secret: string; 13 | access_token: string; 14 | access_token_secret: string; 15 | image_prefix?: string; 16 | } 17 | 18 | type InjectedDependencies = { 19 | manager: EntityManager; 20 | logger: Logger; 21 | } 22 | 23 | export type MagentoFilters = { 24 | field: string; 25 | value: string; 26 | condition_type?: string; 27 | } 28 | 29 | type SearchCriteria = { 30 | currentPage: number; 31 | filterGroups?: MagentoFilters[][]; 32 | storeId?: string; 33 | currencyCode?: string; 34 | } 35 | 36 | export enum MagentoProductTypes { 37 | CONFIGURABLE = 'configurable', 38 | SIMPLE = 'simple' 39 | } 40 | 41 | class MagentoClientService extends TransactionBaseService { 42 | declare protected manager_: EntityManager; 43 | declare protected transactionManager_: EntityManager; 44 | protected logger_: Logger; 45 | protected apiBaseUrl_: string; 46 | protected options_: PluginOptions; 47 | protected client_: AxiosInstance; 48 | protected defaultStoreId_: string; 49 | protected defaultCurrencyCode_: string; 50 | protected defaultImagePrefix_: string; 51 | 52 | constructor(container: InjectedDependencies, options: PluginOptions) { 53 | super(container); 54 | this.manager_ = container.manager 55 | this.logger_ = container.logger; 56 | this.options_ = options; 57 | this.apiBaseUrl_ = `${options.magento_url}/rest/default/V1` 58 | 59 | this.client_ = axios.create({ 60 | headers: { 61 | 'Accept': 'application/json' 62 | } 63 | }); 64 | 65 | addOAuthInterceptor(this.client_, { 66 | algorithm: 'HMAC-SHA256', 67 | key: options.consumer_key, 68 | secret: options.consumer_secret, 69 | token: options.access_token, 70 | tokenSecret: options.access_token_secret 71 | }); 72 | 73 | this.client_.interceptors.request.use(null, (error) => { 74 | console.log(error); 75 | throw new MedusaError( 76 | MedusaError.Types.UNEXPECTED_STATE, 77 | error.response?.data?.message || error.request?.data?.message || error.message || "An error occurred while sending the request." 78 | ) 79 | }) 80 | 81 | this.client_.interceptors.response.use(null, (error) => { 82 | console.log(error); 83 | throw new MedusaError( 84 | MedusaError.Types.UNEXPECTED_STATE, 85 | error.response?.data?.message || error.request?.data?.message || error.message || "An error occurred while sending the request." 86 | ) 87 | }) 88 | 89 | this.defaultImagePrefix_ = options.image_prefix 90 | } 91 | 92 | async retrieveProducts(type?: MagentoProductTypes, lastUpdatedTime?: string, filters?: MagentoFilters[][]) : Promise[]> { 93 | const searchCriteria: SearchCriteria = { 94 | currentPage: 1, 95 | filterGroups: [] 96 | } 97 | 98 | if (type) { 99 | searchCriteria.filterGroups.push([ 100 | { 101 | field: 'type_id', 102 | value: type, 103 | condition_type: 'eq' 104 | } 105 | ]) 106 | } 107 | 108 | if (lastUpdatedTime) { 109 | searchCriteria.filterGroups.push([ 110 | { 111 | field: 'updated_at', 112 | value: lastUpdatedTime, 113 | condition_type: 'gt' 114 | } 115 | ]) 116 | } 117 | 118 | if (filters) { 119 | filters.forEach((filterGroup) => { 120 | const newFilterGroup: MagentoFilters[] = filterGroup.map((filter) => ({ 121 | field: filter.field, 122 | value: filter.value, 123 | condition_type: filter.condition_type || 'eq' 124 | })); 125 | 126 | searchCriteria.filterGroups.push(newFilterGroup) 127 | }) 128 | } 129 | 130 | return this.sendRequest(`/products?${this.formatSearchCriteriaQuery(searchCriteria)}`) 131 | .then(async ({ data }) => { 132 | await this.retrieveDefaultConfigs(); 133 | let options; 134 | 135 | if (type === MagentoProductTypes.CONFIGURABLE) { 136 | options = await this.retrieveOptions(); 137 | } 138 | 139 | for (let i = 0; i < data.items.length; i++) { 140 | data.items[i].media_gallery_entries = data.items[i].media_gallery_entries?.map((entry) => { 141 | entry.url = `${this.defaultImagePrefix_}${entry.file}` 142 | 143 | return entry 144 | }) 145 | 146 | if (data.items[i].extension_attributes?.configurable_product_options) { 147 | data.items[i].extension_attributes?.configurable_product_options.forEach((option) => { 148 | option.values = options.find((o) => o.attribute_id == option.attribute_id)?.options || [] 149 | }) 150 | } 151 | 152 | if (type === MagentoProductTypes.SIMPLE) { 153 | const response = await this.retrieveInventoryData(data.items[i].sku) 154 | data.items[i].stockData = response.data; 155 | } 156 | } 157 | 158 | return data.items; 159 | }) 160 | } 161 | 162 | async retrieveProductImages(items: Record[]): Promise[]> { 163 | if (!this.defaultStoreId_ || !this.defaultCurrencyCode_) { 164 | throw new MedusaError( 165 | MedusaError.Types.INVALID_DATA, 166 | "Default Store ID and Default Currency Code must be set first." 167 | ) 168 | } 169 | 170 | const { data } = await this.sendRequest(`/products-render-info?${this.formatSearchCriteriaQuery({ 171 | currentPage: 1, 172 | filterGroups: [ 173 | [ 174 | { 175 | field: 'entity_id', 176 | value: items.map((item) => item.id).join(','), 177 | condition_type: 'in' 178 | } 179 | ] 180 | ], 181 | storeId: this.defaultStoreId_, 182 | currencyCode: this.defaultCurrencyCode_ 183 | })}`) 184 | 185 | return items.map((item) => { 186 | const itemData = data.items.find((i) => i.id == item.id) 187 | if (itemData) { 188 | item.images = itemData.images || [] 189 | } 190 | 191 | return item; 192 | }); 193 | } 194 | 195 | async retrieveDefaultConfigs() { 196 | if (this.defaultImagePrefix_) { 197 | return; 198 | } 199 | 200 | const { data } = await this.sendRequest(`/store/storeConfigs`) 201 | 202 | const defaultStore = data.length ? data.find((store) => store.code === 'default') : data 203 | 204 | if (!this.defaultImagePrefix_) { 205 | this.defaultImagePrefix_ = `${defaultStore.base_media_url}catalog/product` 206 | } 207 | } 208 | 209 | async retrieveOptionValues (title: string) : Promise[]> { 210 | return this.sendRequest(`/products/attributes/${title}`) 211 | .then(({ data }) => { 212 | return data.options.filter((values) => values.value.length > 0); 213 | }) 214 | } 215 | 216 | async retrieveOptions () : Promise[]> { 217 | const searchCriteria: SearchCriteria = { 218 | currentPage: 1 219 | } 220 | 221 | return this.sendRequest(`/products/attributes?${this.formatSearchCriteriaQuery(searchCriteria)}`) 222 | .then(({ data }) => { 223 | return data.items; 224 | }) 225 | } 226 | 227 | async retrieveInventoryData (sku: string) : Promise> { 228 | return this.sendRequest(`/stockItems/${encodeURIComponent(sku)}`); 229 | } 230 | 231 | async retrieveSimpleProductsAsVariants (productIds: string[]) : Promise[]> { 232 | return this.retrieveProducts(MagentoProductTypes.SIMPLE, null, [ 233 | [ 234 | { 235 | field: 'entity_id', 236 | value: productIds.join(','), 237 | condition_type: 'in' 238 | } 239 | ] 240 | ]) 241 | .then(async (products) => { 242 | return await Promise.all(products.map(async (variant) => { 243 | //get stock item of that variant 244 | const { data } = await this.retrieveInventoryData(variant.sku) 245 | 246 | return { 247 | ...variant, 248 | stockData: data 249 | } 250 | })) 251 | }) 252 | } 253 | 254 | async retrieveCategories (lastUpdatedTime?: string) : Promise> { 255 | const searchCriteria: SearchCriteria = { 256 | currentPage: 1, 257 | filterGroups: [ 258 | [ 259 | { 260 | field: 'name', 261 | value: 'Root Catalog,Default Category', 262 | condition_type: 'nin' 263 | } 264 | ] 265 | ] 266 | } 267 | 268 | if (lastUpdatedTime) { 269 | searchCriteria.filterGroups.push([ 270 | { 271 | field: 'updated_at', 272 | value: lastUpdatedTime, 273 | condition_type: 'gt' 274 | } 275 | ]) 276 | } 277 | 278 | return this.sendRequest(`/categories/list?${this.formatSearchCriteriaQuery(searchCriteria)}`) 279 | } 280 | 281 | async sendRequest (path: string, method: Method = 'GET', data?: Record) : Promise> { 282 | return this.client_.request({ 283 | url: `${this.apiBaseUrl_}${path}`, 284 | method, 285 | data 286 | }) 287 | } 288 | 289 | formatSearchCriteriaQuery (searchCriteria: SearchCriteria): string { 290 | let query = `searchCriteria[currentPage]=${searchCriteria.currentPage}`; 291 | 292 | if (searchCriteria.filterGroups?.length) { 293 | searchCriteria.filterGroups.map((filterGroup, index) => { 294 | filterGroup.map((filter, filterIndex) => { 295 | query += `&searchCriteria[filterGroups][${index}][filters][${filterIndex}][field]=${filter.field}&searchCriteria[filterGroups][${index}][filters][${filterIndex}][value]=${filter.value}&searchCriteria[filterGroups][${index}][filters][${filterIndex}][condition_type]=${filter.condition_type}`; 296 | }) 297 | }) 298 | } 299 | 300 | if (searchCriteria.storeId) { 301 | query += `&storeId=${searchCriteria.storeId}` 302 | } 303 | 304 | if (searchCriteria.currencyCode) { 305 | query += `¤cyCode=${searchCriteria.currencyCode}` 306 | } 307 | 308 | return query; 309 | } 310 | } 311 | 312 | export default MagentoClientService 313 | -------------------------------------------------------------------------------- /src/services/magento-product.ts: -------------------------------------------------------------------------------- 1 | import { CurrencyService, Product, ProductCollectionService, ProductService, ProductStatus, ProductVariantService, ShippingProfileService, Store, StoreService, TransactionBaseService, ProductVariant } from '@medusajs/medusa'; 2 | import MagentoClientService, { MagentoProductTypes, PluginOptions } from './magento-client'; 3 | 4 | import { EntityManager } from 'typeorm'; 5 | import { CreateProductVariantInput } from '@medusajs/medusa/dist/types/product-variant'; 6 | 7 | type InjectedDependencies = { 8 | productService: ProductService; 9 | magentoClientService: MagentoClientService; 10 | currencyService: CurrencyService; 11 | productVariantService: ProductVariantService; 12 | productCollectionService: ProductCollectionService; 13 | shippingProfileService: ShippingProfileService; 14 | storeService: StoreService; 15 | manager: EntityManager; 16 | } 17 | 18 | class MagentoProductService extends TransactionBaseService { 19 | declare protected manager_: EntityManager; 20 | declare protected transactionManager_: EntityManager; 21 | protected options_: PluginOptions; 22 | protected productService_: ProductService; 23 | protected magentoClientService_: MagentoClientService; 24 | protected currencyService_: CurrencyService; 25 | protected productVariantService_: ProductVariantService; 26 | protected productCollectionService_: ProductCollectionService; 27 | protected shippingProfileService_: ShippingProfileService; 28 | protected storeServices_: StoreService; 29 | protected currencies: string[]; 30 | protected defaultShippingProfileId: string; 31 | 32 | constructor(container: InjectedDependencies, options: PluginOptions) { 33 | super(container); 34 | this.manager_ = container.manager; 35 | this.options_ = options; 36 | this.productService_ = container.productService; 37 | this.magentoClientService_ = container.magentoClientService; 38 | this.currencyService_ = container.currencyService; 39 | this.productVariantService_ = container.productVariantService; 40 | this.productCollectionService_ = container.productCollectionService; 41 | this.shippingProfileService_ = container.shippingProfileService; 42 | this.storeServices_ = container.storeService; 43 | 44 | this.currencies = []; 45 | this.defaultShippingProfileId = ""; 46 | } 47 | 48 | async create (productData: any): Promise { 49 | return this.atomicPhase_(async (manager) => { 50 | 51 | //check if product exists 52 | const existingProduct: Product = await this.productService_ 53 | .withTransaction(manager) 54 | .retrieveByExternalId(productData.id, { 55 | relations: ["variants", "options", "images"], 56 | }) 57 | .catch(() => undefined); 58 | 59 | if (existingProduct) { 60 | //update the product instead 61 | return this.update(productData, existingProduct); 62 | } else { 63 | //check if it's a variant 64 | const existingVariant: ProductVariant = await this.productVariantService_ 65 | .withTransaction(manager) 66 | .retrieveBySKU(productData.sku) 67 | .catch(() => undefined) 68 | 69 | if (existingVariant) { 70 | return this.updateVariant(productData, existingVariant); 71 | } 72 | } 73 | 74 | //retrieve store's currencies 75 | await this.getCurrencies(); 76 | 77 | const normalizedProduct = this.normalizeProduct(productData); 78 | normalizedProduct.profile_id = await this.getDefaultShippingProfile(); 79 | 80 | if (productData.extension_attributes?.category_links) { 81 | await this.setCategory(productData.extension_attributes?.category_links, normalizedProduct, manager) 82 | } 83 | 84 | if (productData.extension_attributes?.configurable_product_options) { 85 | //retrieve options 86 | productData.extension_attributes?.configurable_product_options.map((item) => { 87 | normalizedProduct.options.push(this.normalizeOption(item)) 88 | }) 89 | } 90 | 91 | let productImages = normalizedProduct.images; 92 | delete normalizedProduct.images; 93 | 94 | //create product 95 | let product = await this.productService_ 96 | .withTransaction(manager) 97 | .create(normalizedProduct); 98 | 99 | if (productData.extension_attributes?.configurable_product_links) { 100 | //insert the configurable product's simple products as variants 101 | //re-retrieve product with options 102 | product = await this.productService_ 103 | .withTransaction(manager) 104 | .retrieve(product.id, { 105 | relations: ['options'] 106 | }); 107 | 108 | //attached option id to normalized options 109 | normalizedProduct.options = normalizedProduct.options.map((option) => { 110 | const productOption = product.options.find((o) => o.title === option.title); 111 | 112 | return { 113 | ...option, 114 | id: productOption.id 115 | } 116 | }) 117 | 118 | //retrieve simple products as variants 119 | const variants = await this.magentoClientService_ 120 | .retrieveSimpleProductsAsVariants(productData.extension_attributes?.configurable_product_links); 121 | 122 | for (let v of variants) { 123 | const variantData = this.normalizeVariant(v, normalizedProduct.options) 124 | await this.productVariantService_ 125 | .withTransaction(manager) 126 | .create(product.id, variantData as CreateProductVariantInput) 127 | 128 | if (v.media_gallery_entries) { 129 | //update products images with variant's images 130 | productImages.push(...v.media_gallery_entries.map((entry) => entry.url)); 131 | } 132 | } 133 | 134 | } else { 135 | //insert a default variant for a simple product 136 | 137 | const variantData = this.normalizeVariant(productData, []); 138 | 139 | await this.productVariantService_ 140 | .withTransaction(manager) 141 | .create(product.id, variantData as CreateProductVariantInput) 142 | 143 | } 144 | 145 | //insert product images 146 | productImages = [...new Set(productImages)]; 147 | 148 | await this.productService_ 149 | .withTransaction(manager) 150 | .update(product.id, { 151 | images: productImages 152 | }) 153 | }) 154 | } 155 | 156 | async update (productData: any, existingProduct: Product): Promise { 157 | return this.atomicPhase_(async (manager) => { 158 | 159 | //retrieve store's currencies 160 | await this.getCurrencies(); 161 | 162 | const normalizedProduct = this.normalizeProduct(productData); 163 | let productOptions = existingProduct.options; 164 | 165 | if (productData.extension_attributes?.category_links) { 166 | await this.setCategory(productData.extension_attributes?.category_links, normalizedProduct, manager) 167 | } 168 | 169 | if (productData.extension_attributes?.configurable_product_options) { 170 | //retrieve options 171 | productData.extension_attributes.configurable_product_options.forEach(async (item) => { 172 | const existingOption = productOptions.find((o) => o.metadata.magento_id == item.id) 173 | 174 | if (!existingOption) { 175 | //add option 176 | await this.productService_ 177 | .withTransaction(manager) 178 | .addOption(existingProduct.id, item.label) 179 | } 180 | 181 | //update option and its values 182 | const normalizedOption = this.normalizeOption(item) 183 | delete normalizedOption.values 184 | 185 | await this.productService_ 186 | .withTransaction(manager) 187 | .updateOption(existingProduct.id, existingOption.id, normalizedOption) 188 | }) 189 | 190 | //check if there are options that should be deleted 191 | const optionsToDelete = productOptions.filter( 192 | (o) => !productData.extension_attributes?.configurable_product_options.find((magento_option) => magento_option.id == o.metadata.magento_id)) 193 | 194 | optionsToDelete.forEach(async (option) => { 195 | await this.productService_ 196 | .withTransaction(manager) 197 | .deleteOption(existingProduct.id, option.id) 198 | }) 199 | 200 | //re-retrieve product options 201 | productOptions = (await this.productService_ 202 | .withTransaction(manager) 203 | .retrieveByExternalId(productData.id, { 204 | relations: ["options", "options.values"], 205 | })).options; 206 | } 207 | 208 | let productImages = existingProduct.images.map((image) => image.url) 209 | 210 | if (productData.extension_attributes?.configurable_product_links) { 211 | //attach values to the options 212 | productOptions = productOptions.map((productOption) => { 213 | const productDataOption = productData.options.find((o) => productOption.metadata.magento_id == o.id) 214 | if (productDataOption) { 215 | productOption.values = this.normalizeOption(productDataOption).values 216 | } 217 | 218 | return productOption; 219 | }) 220 | 221 | //retrieve simple products as variants 222 | const variants = await this.magentoClientService_ 223 | .retrieveSimpleProductsAsVariants(productData.extension_attributes.configurable_product_links); 224 | 225 | for (let v of variants) { 226 | const variantData = await this.normalizeVariant(v, productOptions) 227 | 228 | //check if variant exists 229 | const existingVariant = existingProduct.variants.find((variant) => variant.metadata.magento_id === v.id) 230 | if (existingVariant) { 231 | //update variant 232 | await this.productVariantService_ 233 | .withTransaction(manager) 234 | .update(existingVariant.id, variantData) 235 | } else { 236 | //create variant 237 | await this.productVariantService_ 238 | .withTransaction(manager) 239 | .create(existingProduct.id, variantData as CreateProductVariantInput) 240 | } 241 | 242 | if (v.media_gallery_entries) { 243 | productImages.push(...v.media_gallery_entries.map((entry) => entry.url)) 244 | } 245 | } 246 | 247 | //check if any variants should be deleted 248 | const variantsToDelete = existingProduct.variants.filter( 249 | (v) => productData.extension_attributes.configurable_product_links.indexOf(v.metadata.magento_id) === -1 250 | ) 251 | 252 | variantsToDelete.forEach(async (variant) => { 253 | await this.productVariantService_ 254 | .withTransaction(manager) 255 | .delete(variant.id) 256 | }) 257 | } else { 258 | //insert or update a default variant for a simple product 259 | 260 | const variantData = await this.normalizeVariant(productData, []); 261 | 262 | if (existingProduct.variants.length) { 263 | await this.productVariantService_ 264 | .withTransaction(manager) 265 | .update(existingProduct.variants[0].id, variantData) 266 | } else { 267 | await this.productVariantService_ 268 | .withTransaction(manager) 269 | .create(existingProduct.id, variantData as CreateProductVariantInput) 270 | } 271 | } 272 | 273 | productImages = [...new Set(productImages)]; 274 | 275 | //update product 276 | delete normalizedProduct.options 277 | delete normalizedProduct.images 278 | 279 | const update = {} 280 | 281 | for (const key of Object.keys(normalizedProduct)) { 282 | if (normalizedProduct[key] !== existingProduct[key]) { 283 | update[key] = normalizedProduct[key] 284 | } 285 | } 286 | 287 | normalizedProduct.images = productImages 288 | 289 | if (Object.values(update).length) { 290 | await this.productService_ 291 | .withTransaction(manager) 292 | .update(existingProduct.id, update) 293 | } 294 | }) 295 | } 296 | 297 | async updateVariant (productData: any, existingVariant: ProductVariant): Promise { 298 | return this.atomicPhase_(async (manager: EntityManager) => { 299 | 300 | //retrieve store's currencies 301 | await this.getCurrencies(); 302 | 303 | const variantData = await this.normalizeVariant(productData, []); 304 | delete variantData.options 305 | delete variantData.magento_id 306 | 307 | const update = {} 308 | 309 | for (const key of Object.keys(variantData)) { 310 | if (variantData[key] !== existingVariant[key]) { 311 | update[key] = variantData[key] 312 | } 313 | } 314 | 315 | if (Object.values(update).length) { 316 | await this.productVariantService_ 317 | .withTransaction(manager) 318 | .update(existingVariant.id, variantData) 319 | } 320 | }) 321 | } 322 | 323 | async getCurrencies () { 324 | if (this.currencies.length) { 325 | return; 326 | } 327 | 328 | const defaultStore: Store = await this.storeServices_.retrieve({ relations: ['currencies', 'default_currency'] }); 329 | this.currencies = [] 330 | 331 | this.currencies.push(...defaultStore.currencies?.map((currency) => currency.code) || []) 332 | this.currencies.push(defaultStore.default_currency?.code) 333 | } 334 | 335 | async getDefaultShippingProfile (): Promise { 336 | if (!this.defaultShippingProfileId.length) { 337 | this.defaultShippingProfileId = (await this.shippingProfileService_.retrieveDefault()).id; 338 | } 339 | 340 | return this.defaultShippingProfileId; 341 | } 342 | 343 | async setCategory (categories: Record[], product: Record, manager: EntityManager) { 344 | //Magento supports multiple categories for a product 345 | //since Medusa supports only one collection for a product, we'll 346 | //use the category with the highest position 347 | 348 | categories.sort((a, b) => { 349 | if (a.position > b.position) { 350 | return 1; 351 | } 352 | 353 | return a.position < b.position ? -1 : 0; 354 | }) 355 | 356 | //retrieve Medusa collection using magento ID 357 | const [_, count] = await this.productCollectionService_ 358 | .withTransaction(manager) 359 | .listAndCount() 360 | 361 | const existingCollections = await this.productCollectionService_ 362 | .withTransaction(manager) 363 | .list({}, { 364 | skip: 0, 365 | take: count 366 | }); 367 | 368 | if (existingCollections.length) { 369 | product.collection_id = existingCollections.find((collection) => { 370 | for (let category of categories) { 371 | if (collection.metadata.magento_id == category.category_id) { 372 | return true; 373 | } 374 | } 375 | 376 | return false; 377 | })?.id 378 | } 379 | 380 | return product; 381 | } 382 | 383 | normalizeProduct(product: Record): any { 384 | return { 385 | title: product.name, 386 | handle: product.custom_attributes?.find((attribute) => attribute.attribute_code === 'url_key')?.value, 387 | description: this.removeHtmlTags(product.custom_attributes?.find((attribute) => attribute.attribute_code === 'description')?.value || ''), 388 | type: { 389 | value: product.type_id 390 | }, 391 | external_id: product.id, 392 | status: product.status == 1 ? ProductStatus.PUBLISHED : ProductStatus.DRAFT, 393 | images: product.media_gallery_entries?.map((img) => img.url) || [], 394 | thumbnail: product.media_gallery_entries?.find((img) => img.types.includes('thumbnail'))?.url, 395 | options: [], 396 | collection_id: null 397 | }; 398 | } 399 | 400 | normalizeVariant (variant: Record, options?: Record[]): Record { 401 | return { 402 | title: variant.name, 403 | prices: this.currencies.map((currency) => ({ 404 | amount: this.parsePrice(variant.price), 405 | currency_code: currency 406 | })), 407 | sku: variant.sku, 408 | inventory_quantity: variant.stockData.qty, 409 | allow_backorder: variant.stockData.backorders > 0, 410 | manage_inventory: variant.stockData.manage_stock, 411 | weight: variant.weight || 0, 412 | options: options?.map((option) => { 413 | const variantOption = variant.custom_attributes?.find((attribute) => attribute.attribute_code.toLowerCase() === option.title.toLowerCase()) 414 | if (variantOption) { 415 | return { 416 | option_id: option.id, 417 | value: option.values.find((value) => value.metadata?.magento_value === variantOption.value)?.value 418 | } 419 | } 420 | }), 421 | metadata: { 422 | magento_id: variant.id 423 | } 424 | } 425 | } 426 | 427 | normalizeOption (option: Record): any { 428 | return { 429 | title: option.label, 430 | values: option.values.map((value) => ({ 431 | value: value.label, 432 | metadata: { 433 | magento_value: value.value, 434 | } 435 | })), 436 | metadata: { 437 | magento_id: option.id 438 | } 439 | } 440 | } 441 | 442 | parsePrice(price: any): number { 443 | return parseInt((parseFloat(Number(price).toFixed(2)) * 100).toString()); 444 | } 445 | 446 | removeHtmlTags(str: string): string { 447 | if ((str===null) || (str==='')) { 448 | return ''; 449 | } 450 | 451 | str = str.toString(); 452 | 453 | // Regular expression to identify HTML tags in 454 | // the input string. Replacing the identified 455 | // HTML tag with a null string. 456 | return str.replace( /(<([^>]+)>)/ig, ''); 457 | } 458 | } 459 | 460 | export default MagentoProductService -------------------------------------------------------------------------------- /src/strategies/import.ts: -------------------------------------------------------------------------------- 1 | import { AbstractBatchJobStrategy, BatchJob, BatchJobService, ProductVariantService, Store, StoreService } from '@medusajs/medusa' 2 | import MagentoClientService, { MagentoProductTypes } from '../services/magento-client'; 3 | 4 | import { EntityManager } from 'typeorm' 5 | import { Logger } from '@medusajs/medusa/dist/types/global'; 6 | import MagentoCategoryService from '../services/magento-category'; 7 | import MagentoProductService from '../services/magento-product'; 8 | 9 | type InjectedDependencies = { 10 | storeService: StoreService; 11 | magentoProductService: MagentoProductService; 12 | magentoClientService: MagentoClientService; 13 | magentoCategoryService: MagentoCategoryService; 14 | productVariantService: ProductVariantService; 15 | logger: Logger; 16 | manager: EntityManager; 17 | batchJobService: BatchJobService; 18 | } 19 | 20 | class ImportStrategy extends AbstractBatchJobStrategy { 21 | static identifier = 'import-magento-strategy' 22 | static batchType = 'import-magento' 23 | 24 | protected batchJobService_: BatchJobService 25 | protected storeService_: StoreService; 26 | protected magentoProductService_: MagentoProductService; 27 | protected magentoClientService_: MagentoClientService; 28 | protected magentoCategoryService_: MagentoCategoryService; 29 | protected productVariantService: ProductVariantService; 30 | protected logger_: Logger; 31 | 32 | constructor(container: InjectedDependencies) { 33 | super(container); 34 | 35 | this.manager_ = container.manager; 36 | this.storeService_ = container.storeService; 37 | this.magentoProductService_ = container.magentoProductService; 38 | this.magentoClientService_ = container.magentoClientService; 39 | this.magentoCategoryService_ = container.magentoCategoryService; 40 | this.productVariantService = container.productVariantService; 41 | this.logger_ = container.logger; 42 | this.batchJobService_ = container.batchJobService; 43 | } 44 | 45 | async preProcessBatchJob(batchJobId: string): Promise { 46 | return await this.atomicPhase_(async (transactionManager) => { 47 | const batchJob = (await this.batchJobService_ 48 | .withTransaction(transactionManager) 49 | .retrieve(batchJobId)) 50 | 51 | await this.batchJobService_ 52 | .withTransaction(transactionManager) 53 | .update(batchJob, { 54 | result: { 55 | progress: 0 56 | } 57 | }) 58 | }) 59 | } 60 | 61 | async processJob(batchJobId: string): Promise { 62 | const batchJob = (await this.batchJobService_ 63 | .retrieve(batchJobId)) 64 | 65 | let store: Store 66 | 67 | try { 68 | store = await this.storeService_.retrieve(); 69 | } catch (e) { 70 | this.logger_.info('Skipping Magento import since no store is created in Medusa.'); 71 | return; 72 | } 73 | 74 | this.logger_.info('Importing categories from Magento...') 75 | const lastUpdatedTime = await this.getBuildTime(store) 76 | 77 | //retrieve categories 78 | const { data } = await this.magentoClientService_.retrieveCategories(lastUpdatedTime); 79 | 80 | data.items.map(async (category) => { 81 | return this.magentoCategoryService_ 82 | .create(category); 83 | }) 84 | 85 | if (data.items.length) { 86 | this.logger_.info(`${data.items.length} categories have been imported or updated successfully.`) 87 | } else { 88 | this.logger_.info(`No categories have been imported or updated.`) 89 | } 90 | 91 | this.logger_.info('Importing products from Magento...') 92 | 93 | //retrieve configurable products 94 | const products = await this.magentoClientService_.retrieveProducts(MagentoProductTypes.CONFIGURABLE, lastUpdatedTime); 95 | 96 | for (let product of products) { 97 | await this.magentoProductService_ 98 | .create(product); 99 | } 100 | 101 | //retrieve simple products to insert those that don't belong to a configurable product 102 | const simpleProducts = await this.magentoClientService_.retrieveProducts(MagentoProductTypes.SIMPLE, lastUpdatedTime); 103 | 104 | for (let product of simpleProducts) { 105 | await this.magentoProductService_ 106 | .create(product); 107 | } 108 | 109 | if (products.length || simpleProducts.length) { 110 | this.logger_.info(`${products.length + simpleProducts.length} products have been imported or updated successfully.`) 111 | } else { 112 | this.logger_.info(`No products have been imported or updated.`) 113 | } 114 | 115 | await this.updateBuildTime(store); 116 | } 117 | 118 | async getBuildTime(store?: Store|null): Promise { 119 | let buildtime = null 120 | 121 | try { 122 | if (!store) { 123 | store = await this.storeService_.retrieve() 124 | } 125 | } catch { 126 | return null 127 | } 128 | 129 | if (store.metadata?.source_magento_bt) { 130 | buildtime = store.metadata.source_magento_bt 131 | } 132 | 133 | if (!buildtime) { 134 | return null 135 | } 136 | 137 | return buildtime 138 | } 139 | 140 | async updateBuildTime (store?: Store|null): Promise { 141 | try { 142 | if (!store) { 143 | store = await this.storeService_.retrieve() 144 | } 145 | } catch { 146 | return null 147 | } 148 | 149 | const payload = { 150 | metadata: { 151 | source_magento_bt: new Date().toISOString(), 152 | }, 153 | } 154 | 155 | await this.storeService_.update(payload) 156 | } 157 | 158 | protected async shouldRetryOnProcessingError(batchJob: BatchJob, err: unknown): Promise { 159 | return true 160 | } 161 | 162 | buildTemplate(): Promise { 163 | throw new Error('Method not implemented.') 164 | } 165 | declare protected manager_: EntityManager 166 | declare protected transactionManager_: EntityManager 167 | 168 | } 169 | 170 | export default ImportStrategy -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es5", "es6"], 4 | "target": "esnext", 5 | "allowJs": true, 6 | "esModuleInterop": true, 7 | "module": "commonjs", 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "skipLibCheck": true, 12 | "skipDefaultLibCheck": true, 13 | "declaration": false, 14 | "sourceMap": false, 15 | "outDir": "./dist", 16 | "rootDir": "src", 17 | "baseUrl": "src" 18 | }, 19 | "include": ["src"], 20 | "exclude": [ 21 | "**/__tests__", 22 | "**/__fixtures__", 23 | "node_modules" 24 | ] 25 | } -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@ampproject/remapping@^2.1.0": 6 | version "2.2.0" 7 | resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz" 8 | dependencies: 9 | "@jridgewell/gen-mapping" "^0.1.0" 10 | "@jridgewell/trace-mapping" "^0.3.9" 11 | 12 | "@babel/cli@^7.14.3": 13 | version "7.19.3" 14 | resolved "https://registry.npmjs.org/@babel/cli/-/cli-7.19.3.tgz" 15 | dependencies: 16 | "@jridgewell/trace-mapping" "^0.3.8" 17 | commander "^4.0.1" 18 | convert-source-map "^1.1.0" 19 | fs-readdir-recursive "^1.1.0" 20 | glob "^7.2.0" 21 | make-dir "^2.1.0" 22 | slash "^2.0.0" 23 | optionalDependencies: 24 | "@nicolo-ribaudo/chokidar-2" "2.1.8-no-fsevents.3" 25 | chokidar "^3.4.0" 26 | 27 | "@babel/code-frame@^7.18.6": 28 | version "7.18.6" 29 | resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz" 30 | dependencies: 31 | "@babel/highlight" "^7.18.6" 32 | 33 | "@babel/compat-data@^7.17.7", "@babel/compat-data@^7.19.3", "@babel/compat-data@^7.19.4": 34 | version "7.19.4" 35 | resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.4.tgz" 36 | 37 | "@babel/core@^7.14.3": 38 | version "7.19.3" 39 | resolved "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz" 40 | dependencies: 41 | "@ampproject/remapping" "^2.1.0" 42 | "@babel/code-frame" "^7.18.6" 43 | "@babel/generator" "^7.19.3" 44 | "@babel/helper-compilation-targets" "^7.19.3" 45 | "@babel/helper-module-transforms" "^7.19.0" 46 | "@babel/helpers" "^7.19.0" 47 | "@babel/parser" "^7.19.3" 48 | "@babel/template" "^7.18.10" 49 | "@babel/traverse" "^7.19.3" 50 | "@babel/types" "^7.19.3" 51 | convert-source-map "^1.7.0" 52 | debug "^4.1.0" 53 | gensync "^1.0.0-beta.2" 54 | json5 "^2.2.1" 55 | semver "^6.3.0" 56 | 57 | "@babel/generator@^7.19.3", "@babel/generator@^7.19.4": 58 | version "7.19.5" 59 | resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.19.5.tgz" 60 | dependencies: 61 | "@babel/types" "^7.19.4" 62 | "@jridgewell/gen-mapping" "^0.3.2" 63 | jsesc "^2.5.1" 64 | 65 | "@babel/helper-annotate-as-pure@^7.18.6": 66 | version "7.18.6" 67 | resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz" 68 | dependencies: 69 | "@babel/types" "^7.18.6" 70 | 71 | "@babel/helper-builder-binary-assignment-operator-visitor@^7.18.6": 72 | version "7.18.9" 73 | resolved "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz" 74 | dependencies: 75 | "@babel/helper-explode-assignable-expression" "^7.18.6" 76 | "@babel/types" "^7.18.9" 77 | 78 | "@babel/helper-compilation-targets@^7.17.7", "@babel/helper-compilation-targets@^7.18.9", "@babel/helper-compilation-targets@^7.19.0", "@babel/helper-compilation-targets@^7.19.3": 79 | version "7.19.3" 80 | resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz" 81 | dependencies: 82 | "@babel/compat-data" "^7.19.3" 83 | "@babel/helper-validator-option" "^7.18.6" 84 | browserslist "^4.21.3" 85 | semver "^6.3.0" 86 | 87 | "@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.19.0": 88 | version "7.19.0" 89 | resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz" 90 | dependencies: 91 | "@babel/helper-annotate-as-pure" "^7.18.6" 92 | "@babel/helper-environment-visitor" "^7.18.9" 93 | "@babel/helper-function-name" "^7.19.0" 94 | "@babel/helper-member-expression-to-functions" "^7.18.9" 95 | "@babel/helper-optimise-call-expression" "^7.18.6" 96 | "@babel/helper-replace-supers" "^7.18.9" 97 | "@babel/helper-split-export-declaration" "^7.18.6" 98 | 99 | "@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.19.0": 100 | version "7.19.0" 101 | resolved "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz" 102 | dependencies: 103 | "@babel/helper-annotate-as-pure" "^7.18.6" 104 | regexpu-core "^5.1.0" 105 | 106 | "@babel/helper-define-polyfill-provider@^0.3.3": 107 | version "0.3.3" 108 | resolved "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz" 109 | dependencies: 110 | "@babel/helper-compilation-targets" "^7.17.7" 111 | "@babel/helper-plugin-utils" "^7.16.7" 112 | debug "^4.1.1" 113 | lodash.debounce "^4.0.8" 114 | resolve "^1.14.2" 115 | semver "^6.1.2" 116 | 117 | "@babel/helper-environment-visitor@^7.18.9": 118 | version "7.18.9" 119 | resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz" 120 | 121 | "@babel/helper-explode-assignable-expression@^7.18.6": 122 | version "7.18.6" 123 | resolved "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz" 124 | dependencies: 125 | "@babel/types" "^7.18.6" 126 | 127 | "@babel/helper-function-name@^7.18.9", "@babel/helper-function-name@^7.19.0": 128 | version "7.19.0" 129 | resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz" 130 | dependencies: 131 | "@babel/template" "^7.18.10" 132 | "@babel/types" "^7.19.0" 133 | 134 | "@babel/helper-hoist-variables@^7.18.6": 135 | version "7.18.6" 136 | resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz" 137 | dependencies: 138 | "@babel/types" "^7.18.6" 139 | 140 | "@babel/helper-member-expression-to-functions@^7.18.9": 141 | version "7.18.9" 142 | resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz" 143 | dependencies: 144 | "@babel/types" "^7.18.9" 145 | 146 | "@babel/helper-module-imports@^7.18.6": 147 | version "7.18.6" 148 | resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz" 149 | dependencies: 150 | "@babel/types" "^7.18.6" 151 | 152 | "@babel/helper-module-transforms@^7.18.6", "@babel/helper-module-transforms@^7.19.0": 153 | version "7.19.0" 154 | resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz" 155 | dependencies: 156 | "@babel/helper-environment-visitor" "^7.18.9" 157 | "@babel/helper-module-imports" "^7.18.6" 158 | "@babel/helper-simple-access" "^7.18.6" 159 | "@babel/helper-split-export-declaration" "^7.18.6" 160 | "@babel/helper-validator-identifier" "^7.18.6" 161 | "@babel/template" "^7.18.10" 162 | "@babel/traverse" "^7.19.0" 163 | "@babel/types" "^7.19.0" 164 | 165 | "@babel/helper-optimise-call-expression@^7.18.6": 166 | version "7.18.6" 167 | resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz" 168 | dependencies: 169 | "@babel/types" "^7.18.6" 170 | 171 | "@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.16.7", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.18.9", "@babel/helper-plugin-utils@^7.19.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": 172 | version "7.19.0" 173 | resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz" 174 | 175 | "@babel/helper-remap-async-to-generator@^7.18.6", "@babel/helper-remap-async-to-generator@^7.18.9": 176 | version "7.18.9" 177 | resolved "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz" 178 | dependencies: 179 | "@babel/helper-annotate-as-pure" "^7.18.6" 180 | "@babel/helper-environment-visitor" "^7.18.9" 181 | "@babel/helper-wrap-function" "^7.18.9" 182 | "@babel/types" "^7.18.9" 183 | 184 | "@babel/helper-replace-supers@^7.18.6", "@babel/helper-replace-supers@^7.18.9", "@babel/helper-replace-supers@^7.19.1": 185 | version "7.19.1" 186 | resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz" 187 | dependencies: 188 | "@babel/helper-environment-visitor" "^7.18.9" 189 | "@babel/helper-member-expression-to-functions" "^7.18.9" 190 | "@babel/helper-optimise-call-expression" "^7.18.6" 191 | "@babel/traverse" "^7.19.1" 192 | "@babel/types" "^7.19.0" 193 | 194 | "@babel/helper-simple-access@^7.18.6": 195 | version "7.19.4" 196 | resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz" 197 | dependencies: 198 | "@babel/types" "^7.19.4" 199 | 200 | "@babel/helper-skip-transparent-expression-wrappers@^7.18.9": 201 | version "7.18.9" 202 | resolved "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz" 203 | dependencies: 204 | "@babel/types" "^7.18.9" 205 | 206 | "@babel/helper-split-export-declaration@^7.18.6": 207 | version "7.18.6" 208 | resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz" 209 | dependencies: 210 | "@babel/types" "^7.18.6" 211 | 212 | "@babel/helper-string-parser@^7.19.4": 213 | version "7.19.4" 214 | resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz" 215 | 216 | "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": 217 | version "7.19.1" 218 | resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz" 219 | 220 | "@babel/helper-validator-option@^7.18.6": 221 | version "7.18.6" 222 | resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz" 223 | 224 | "@babel/helper-wrap-function@^7.18.9": 225 | version "7.19.0" 226 | resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz" 227 | dependencies: 228 | "@babel/helper-function-name" "^7.19.0" 229 | "@babel/template" "^7.18.10" 230 | "@babel/traverse" "^7.19.0" 231 | "@babel/types" "^7.19.0" 232 | 233 | "@babel/helpers@^7.19.0": 234 | version "7.19.4" 235 | resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.4.tgz" 236 | dependencies: 237 | "@babel/template" "^7.18.10" 238 | "@babel/traverse" "^7.19.4" 239 | "@babel/types" "^7.19.4" 240 | 241 | "@babel/highlight@^7.18.6": 242 | version "7.18.6" 243 | resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz" 244 | dependencies: 245 | "@babel/helper-validator-identifier" "^7.18.6" 246 | chalk "^2.0.0" 247 | js-tokens "^4.0.0" 248 | 249 | "@babel/parser@^7.18.10", "@babel/parser@^7.19.3", "@babel/parser@^7.19.4": 250 | version "7.19.4" 251 | resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.19.4.tgz" 252 | 253 | "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": 254 | version "7.18.6" 255 | resolved "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz" 256 | dependencies: 257 | "@babel/helper-plugin-utils" "^7.18.6" 258 | 259 | "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.18.9": 260 | version "7.18.9" 261 | resolved "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz" 262 | dependencies: 263 | "@babel/helper-plugin-utils" "^7.18.9" 264 | "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" 265 | "@babel/plugin-proposal-optional-chaining" "^7.18.9" 266 | 267 | "@babel/plugin-proposal-async-generator-functions@^7.19.1": 268 | version "7.19.1" 269 | resolved "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.19.1.tgz" 270 | dependencies: 271 | "@babel/helper-environment-visitor" "^7.18.9" 272 | "@babel/helper-plugin-utils" "^7.19.0" 273 | "@babel/helper-remap-async-to-generator" "^7.18.9" 274 | "@babel/plugin-syntax-async-generators" "^7.8.4" 275 | 276 | "@babel/plugin-proposal-class-properties@^7.12.1", "@babel/plugin-proposal-class-properties@^7.18.6": 277 | version "7.18.6" 278 | resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz" 279 | dependencies: 280 | "@babel/helper-create-class-features-plugin" "^7.18.6" 281 | "@babel/helper-plugin-utils" "^7.18.6" 282 | 283 | "@babel/plugin-proposal-class-static-block@^7.18.6": 284 | version "7.18.6" 285 | resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz" 286 | dependencies: 287 | "@babel/helper-create-class-features-plugin" "^7.18.6" 288 | "@babel/helper-plugin-utils" "^7.18.6" 289 | "@babel/plugin-syntax-class-static-block" "^7.14.5" 290 | 291 | "@babel/plugin-proposal-decorators@^7.12.1": 292 | version "7.19.3" 293 | resolved "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.19.3.tgz" 294 | dependencies: 295 | "@babel/helper-create-class-features-plugin" "^7.19.0" 296 | "@babel/helper-plugin-utils" "^7.19.0" 297 | "@babel/helper-replace-supers" "^7.19.1" 298 | "@babel/helper-split-export-declaration" "^7.18.6" 299 | "@babel/plugin-syntax-decorators" "^7.19.0" 300 | 301 | "@babel/plugin-proposal-dynamic-import@^7.18.6": 302 | version "7.18.6" 303 | resolved "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz" 304 | dependencies: 305 | "@babel/helper-plugin-utils" "^7.18.6" 306 | "@babel/plugin-syntax-dynamic-import" "^7.8.3" 307 | 308 | "@babel/plugin-proposal-export-namespace-from@^7.18.9": 309 | version "7.18.9" 310 | resolved "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz" 311 | dependencies: 312 | "@babel/helper-plugin-utils" "^7.18.9" 313 | "@babel/plugin-syntax-export-namespace-from" "^7.8.3" 314 | 315 | "@babel/plugin-proposal-json-strings@^7.18.6": 316 | version "7.18.6" 317 | resolved "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz" 318 | dependencies: 319 | "@babel/helper-plugin-utils" "^7.18.6" 320 | "@babel/plugin-syntax-json-strings" "^7.8.3" 321 | 322 | "@babel/plugin-proposal-logical-assignment-operators@^7.18.9": 323 | version "7.18.9" 324 | resolved "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz" 325 | dependencies: 326 | "@babel/helper-plugin-utils" "^7.18.9" 327 | "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" 328 | 329 | "@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6": 330 | version "7.18.6" 331 | resolved "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz" 332 | dependencies: 333 | "@babel/helper-plugin-utils" "^7.18.6" 334 | "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" 335 | 336 | "@babel/plugin-proposal-numeric-separator@^7.18.6": 337 | version "7.18.6" 338 | resolved "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz" 339 | dependencies: 340 | "@babel/helper-plugin-utils" "^7.18.6" 341 | "@babel/plugin-syntax-numeric-separator" "^7.10.4" 342 | 343 | "@babel/plugin-proposal-object-rest-spread@^7.19.4": 344 | version "7.19.4" 345 | resolved "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.19.4.tgz" 346 | dependencies: 347 | "@babel/compat-data" "^7.19.4" 348 | "@babel/helper-compilation-targets" "^7.19.3" 349 | "@babel/helper-plugin-utils" "^7.19.0" 350 | "@babel/plugin-syntax-object-rest-spread" "^7.8.3" 351 | "@babel/plugin-transform-parameters" "^7.18.8" 352 | 353 | "@babel/plugin-proposal-optional-catch-binding@^7.18.6": 354 | version "7.18.6" 355 | resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz" 356 | dependencies: 357 | "@babel/helper-plugin-utils" "^7.18.6" 358 | "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" 359 | 360 | "@babel/plugin-proposal-optional-chaining@^7.14.2", "@babel/plugin-proposal-optional-chaining@^7.18.9": 361 | version "7.18.9" 362 | resolved "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz" 363 | dependencies: 364 | "@babel/helper-plugin-utils" "^7.18.9" 365 | "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" 366 | "@babel/plugin-syntax-optional-chaining" "^7.8.3" 367 | 368 | "@babel/plugin-proposal-private-methods@^7.18.6": 369 | version "7.18.6" 370 | resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz" 371 | dependencies: 372 | "@babel/helper-create-class-features-plugin" "^7.18.6" 373 | "@babel/helper-plugin-utils" "^7.18.6" 374 | 375 | "@babel/plugin-proposal-private-property-in-object@^7.18.6": 376 | version "7.18.6" 377 | resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz" 378 | dependencies: 379 | "@babel/helper-annotate-as-pure" "^7.18.6" 380 | "@babel/helper-create-class-features-plugin" "^7.18.6" 381 | "@babel/helper-plugin-utils" "^7.18.6" 382 | "@babel/plugin-syntax-private-property-in-object" "^7.14.5" 383 | 384 | "@babel/plugin-proposal-unicode-property-regex@^7.18.6", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": 385 | version "7.18.6" 386 | resolved "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz" 387 | dependencies: 388 | "@babel/helper-create-regexp-features-plugin" "^7.18.6" 389 | "@babel/helper-plugin-utils" "^7.18.6" 390 | 391 | "@babel/plugin-syntax-async-generators@^7.8.4": 392 | version "7.8.4" 393 | resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" 394 | dependencies: 395 | "@babel/helper-plugin-utils" "^7.8.0" 396 | 397 | "@babel/plugin-syntax-class-properties@^7.12.13": 398 | version "7.12.13" 399 | resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" 400 | dependencies: 401 | "@babel/helper-plugin-utils" "^7.12.13" 402 | 403 | "@babel/plugin-syntax-class-static-block@^7.14.5": 404 | version "7.14.5" 405 | resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz" 406 | dependencies: 407 | "@babel/helper-plugin-utils" "^7.14.5" 408 | 409 | "@babel/plugin-syntax-decorators@^7.19.0": 410 | version "7.19.0" 411 | resolved "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.19.0.tgz" 412 | dependencies: 413 | "@babel/helper-plugin-utils" "^7.19.0" 414 | 415 | "@babel/plugin-syntax-dynamic-import@^7.8.3": 416 | version "7.8.3" 417 | resolved "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz" 418 | dependencies: 419 | "@babel/helper-plugin-utils" "^7.8.0" 420 | 421 | "@babel/plugin-syntax-export-namespace-from@^7.8.3": 422 | version "7.8.3" 423 | resolved "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz" 424 | dependencies: 425 | "@babel/helper-plugin-utils" "^7.8.3" 426 | 427 | "@babel/plugin-syntax-import-assertions@^7.18.6": 428 | version "7.18.6" 429 | resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz" 430 | dependencies: 431 | "@babel/helper-plugin-utils" "^7.18.6" 432 | 433 | "@babel/plugin-syntax-json-strings@^7.8.3": 434 | version "7.8.3" 435 | resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" 436 | dependencies: 437 | "@babel/helper-plugin-utils" "^7.8.0" 438 | 439 | "@babel/plugin-syntax-logical-assignment-operators@^7.10.4": 440 | version "7.10.4" 441 | resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" 442 | dependencies: 443 | "@babel/helper-plugin-utils" "^7.10.4" 444 | 445 | "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": 446 | version "7.8.3" 447 | resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" 448 | dependencies: 449 | "@babel/helper-plugin-utils" "^7.8.0" 450 | 451 | "@babel/plugin-syntax-numeric-separator@^7.10.4": 452 | version "7.10.4" 453 | resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" 454 | dependencies: 455 | "@babel/helper-plugin-utils" "^7.10.4" 456 | 457 | "@babel/plugin-syntax-object-rest-spread@^7.8.3": 458 | version "7.8.3" 459 | resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" 460 | dependencies: 461 | "@babel/helper-plugin-utils" "^7.8.0" 462 | 463 | "@babel/plugin-syntax-optional-catch-binding@^7.8.3": 464 | version "7.8.3" 465 | resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" 466 | dependencies: 467 | "@babel/helper-plugin-utils" "^7.8.0" 468 | 469 | "@babel/plugin-syntax-optional-chaining@^7.8.3": 470 | version "7.8.3" 471 | resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" 472 | dependencies: 473 | "@babel/helper-plugin-utils" "^7.8.0" 474 | 475 | "@babel/plugin-syntax-private-property-in-object@^7.14.5": 476 | version "7.14.5" 477 | resolved "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz" 478 | dependencies: 479 | "@babel/helper-plugin-utils" "^7.14.5" 480 | 481 | "@babel/plugin-syntax-top-level-await@^7.14.5": 482 | version "7.14.5" 483 | resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" 484 | dependencies: 485 | "@babel/helper-plugin-utils" "^7.14.5" 486 | 487 | "@babel/plugin-syntax-typescript@^7.18.6": 488 | version "7.18.6" 489 | resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz" 490 | dependencies: 491 | "@babel/helper-plugin-utils" "^7.18.6" 492 | 493 | "@babel/plugin-transform-arrow-functions@^7.18.6": 494 | version "7.18.6" 495 | resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz" 496 | dependencies: 497 | "@babel/helper-plugin-utils" "^7.18.6" 498 | 499 | "@babel/plugin-transform-async-to-generator@^7.18.6": 500 | version "7.18.6" 501 | resolved "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz" 502 | dependencies: 503 | "@babel/helper-module-imports" "^7.18.6" 504 | "@babel/helper-plugin-utils" "^7.18.6" 505 | "@babel/helper-remap-async-to-generator" "^7.18.6" 506 | 507 | "@babel/plugin-transform-block-scoped-functions@^7.18.6": 508 | version "7.18.6" 509 | resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz" 510 | dependencies: 511 | "@babel/helper-plugin-utils" "^7.18.6" 512 | 513 | "@babel/plugin-transform-block-scoping@^7.19.4": 514 | version "7.19.4" 515 | resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.19.4.tgz" 516 | dependencies: 517 | "@babel/helper-plugin-utils" "^7.19.0" 518 | 519 | "@babel/plugin-transform-classes@^7.12.1", "@babel/plugin-transform-classes@^7.19.0": 520 | version "7.19.0" 521 | resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz" 522 | dependencies: 523 | "@babel/helper-annotate-as-pure" "^7.18.6" 524 | "@babel/helper-compilation-targets" "^7.19.0" 525 | "@babel/helper-environment-visitor" "^7.18.9" 526 | "@babel/helper-function-name" "^7.19.0" 527 | "@babel/helper-optimise-call-expression" "^7.18.6" 528 | "@babel/helper-plugin-utils" "^7.19.0" 529 | "@babel/helper-replace-supers" "^7.18.9" 530 | "@babel/helper-split-export-declaration" "^7.18.6" 531 | globals "^11.1.0" 532 | 533 | "@babel/plugin-transform-computed-properties@^7.18.9": 534 | version "7.18.9" 535 | resolved "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz" 536 | dependencies: 537 | "@babel/helper-plugin-utils" "^7.18.9" 538 | 539 | "@babel/plugin-transform-destructuring@^7.19.4": 540 | version "7.19.4" 541 | resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.19.4.tgz" 542 | dependencies: 543 | "@babel/helper-plugin-utils" "^7.19.0" 544 | 545 | "@babel/plugin-transform-dotall-regex@^7.18.6", "@babel/plugin-transform-dotall-regex@^7.4.4": 546 | version "7.18.6" 547 | resolved "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz" 548 | dependencies: 549 | "@babel/helper-create-regexp-features-plugin" "^7.18.6" 550 | "@babel/helper-plugin-utils" "^7.18.6" 551 | 552 | "@babel/plugin-transform-duplicate-keys@^7.18.9": 553 | version "7.18.9" 554 | resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz" 555 | dependencies: 556 | "@babel/helper-plugin-utils" "^7.18.9" 557 | 558 | "@babel/plugin-transform-exponentiation-operator@^7.18.6": 559 | version "7.18.6" 560 | resolved "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz" 561 | dependencies: 562 | "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6" 563 | "@babel/helper-plugin-utils" "^7.18.6" 564 | 565 | "@babel/plugin-transform-for-of@^7.18.8": 566 | version "7.18.8" 567 | resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz" 568 | dependencies: 569 | "@babel/helper-plugin-utils" "^7.18.6" 570 | 571 | "@babel/plugin-transform-function-name@^7.18.9": 572 | version "7.18.9" 573 | resolved "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz" 574 | dependencies: 575 | "@babel/helper-compilation-targets" "^7.18.9" 576 | "@babel/helper-function-name" "^7.18.9" 577 | "@babel/helper-plugin-utils" "^7.18.9" 578 | 579 | "@babel/plugin-transform-instanceof@^7.12.1": 580 | version "7.18.9" 581 | resolved "https://registry.npmjs.org/@babel/plugin-transform-instanceof/-/plugin-transform-instanceof-7.18.9.tgz" 582 | dependencies: 583 | "@babel/helper-plugin-utils" "^7.18.9" 584 | 585 | "@babel/plugin-transform-literals@^7.18.9": 586 | version "7.18.9" 587 | resolved "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz" 588 | dependencies: 589 | "@babel/helper-plugin-utils" "^7.18.9" 590 | 591 | "@babel/plugin-transform-member-expression-literals@^7.18.6": 592 | version "7.18.6" 593 | resolved "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz" 594 | dependencies: 595 | "@babel/helper-plugin-utils" "^7.18.6" 596 | 597 | "@babel/plugin-transform-modules-amd@^7.18.6": 598 | version "7.18.6" 599 | resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz" 600 | dependencies: 601 | "@babel/helper-module-transforms" "^7.18.6" 602 | "@babel/helper-plugin-utils" "^7.18.6" 603 | babel-plugin-dynamic-import-node "^2.3.3" 604 | 605 | "@babel/plugin-transform-modules-commonjs@^7.18.6": 606 | version "7.18.6" 607 | resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz" 608 | dependencies: 609 | "@babel/helper-module-transforms" "^7.18.6" 610 | "@babel/helper-plugin-utils" "^7.18.6" 611 | "@babel/helper-simple-access" "^7.18.6" 612 | babel-plugin-dynamic-import-node "^2.3.3" 613 | 614 | "@babel/plugin-transform-modules-systemjs@^7.19.0": 615 | version "7.19.0" 616 | resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.0.tgz" 617 | dependencies: 618 | "@babel/helper-hoist-variables" "^7.18.6" 619 | "@babel/helper-module-transforms" "^7.19.0" 620 | "@babel/helper-plugin-utils" "^7.19.0" 621 | "@babel/helper-validator-identifier" "^7.18.6" 622 | babel-plugin-dynamic-import-node "^2.3.3" 623 | 624 | "@babel/plugin-transform-modules-umd@^7.18.6": 625 | version "7.18.6" 626 | resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz" 627 | dependencies: 628 | "@babel/helper-module-transforms" "^7.18.6" 629 | "@babel/helper-plugin-utils" "^7.18.6" 630 | 631 | "@babel/plugin-transform-named-capturing-groups-regex@^7.19.1": 632 | version "7.19.1" 633 | resolved "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz" 634 | dependencies: 635 | "@babel/helper-create-regexp-features-plugin" "^7.19.0" 636 | "@babel/helper-plugin-utils" "^7.19.0" 637 | 638 | "@babel/plugin-transform-new-target@^7.18.6": 639 | version "7.18.6" 640 | resolved "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz" 641 | dependencies: 642 | "@babel/helper-plugin-utils" "^7.18.6" 643 | 644 | "@babel/plugin-transform-object-super@^7.18.6": 645 | version "7.18.6" 646 | resolved "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz" 647 | dependencies: 648 | "@babel/helper-plugin-utils" "^7.18.6" 649 | "@babel/helper-replace-supers" "^7.18.6" 650 | 651 | "@babel/plugin-transform-parameters@^7.18.8": 652 | version "7.18.8" 653 | resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz" 654 | dependencies: 655 | "@babel/helper-plugin-utils" "^7.18.6" 656 | 657 | "@babel/plugin-transform-property-literals@^7.18.6": 658 | version "7.18.6" 659 | resolved "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz" 660 | dependencies: 661 | "@babel/helper-plugin-utils" "^7.18.6" 662 | 663 | "@babel/plugin-transform-regenerator@^7.18.6": 664 | version "7.18.6" 665 | resolved "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz" 666 | dependencies: 667 | "@babel/helper-plugin-utils" "^7.18.6" 668 | regenerator-transform "^0.15.0" 669 | 670 | "@babel/plugin-transform-reserved-words@^7.18.6": 671 | version "7.18.6" 672 | resolved "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz" 673 | dependencies: 674 | "@babel/helper-plugin-utils" "^7.18.6" 675 | 676 | "@babel/plugin-transform-runtime@^7.12.1": 677 | version "7.19.1" 678 | resolved "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.1.tgz" 679 | dependencies: 680 | "@babel/helper-module-imports" "^7.18.6" 681 | "@babel/helper-plugin-utils" "^7.19.0" 682 | babel-plugin-polyfill-corejs2 "^0.3.3" 683 | babel-plugin-polyfill-corejs3 "^0.6.0" 684 | babel-plugin-polyfill-regenerator "^0.4.1" 685 | semver "^6.3.0" 686 | 687 | "@babel/plugin-transform-shorthand-properties@^7.18.6": 688 | version "7.18.6" 689 | resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz" 690 | dependencies: 691 | "@babel/helper-plugin-utils" "^7.18.6" 692 | 693 | "@babel/plugin-transform-spread@^7.19.0": 694 | version "7.19.0" 695 | resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz" 696 | dependencies: 697 | "@babel/helper-plugin-utils" "^7.19.0" 698 | "@babel/helper-skip-transparent-expression-wrappers" "^7.18.9" 699 | 700 | "@babel/plugin-transform-sticky-regex@^7.18.6": 701 | version "7.18.6" 702 | resolved "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz" 703 | dependencies: 704 | "@babel/helper-plugin-utils" "^7.18.6" 705 | 706 | "@babel/plugin-transform-template-literals@^7.18.9": 707 | version "7.18.9" 708 | resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz" 709 | dependencies: 710 | "@babel/helper-plugin-utils" "^7.18.9" 711 | 712 | "@babel/plugin-transform-typeof-symbol@^7.18.9": 713 | version "7.18.9" 714 | resolved "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz" 715 | dependencies: 716 | "@babel/helper-plugin-utils" "^7.18.9" 717 | 718 | "@babel/plugin-transform-typescript@^7.18.6": 719 | version "7.19.3" 720 | resolved "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.19.3.tgz" 721 | dependencies: 722 | "@babel/helper-create-class-features-plugin" "^7.19.0" 723 | "@babel/helper-plugin-utils" "^7.19.0" 724 | "@babel/plugin-syntax-typescript" "^7.18.6" 725 | 726 | "@babel/plugin-transform-unicode-escapes@^7.18.10": 727 | version "7.18.10" 728 | resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz" 729 | dependencies: 730 | "@babel/helper-plugin-utils" "^7.18.9" 731 | 732 | "@babel/plugin-transform-unicode-regex@^7.18.6": 733 | version "7.18.6" 734 | resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz" 735 | dependencies: 736 | "@babel/helper-create-regexp-features-plugin" "^7.18.6" 737 | "@babel/helper-plugin-utils" "^7.18.6" 738 | 739 | "@babel/preset-env@^7.12.7": 740 | version "7.19.4" 741 | resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.19.4.tgz" 742 | dependencies: 743 | "@babel/compat-data" "^7.19.4" 744 | "@babel/helper-compilation-targets" "^7.19.3" 745 | "@babel/helper-plugin-utils" "^7.19.0" 746 | "@babel/helper-validator-option" "^7.18.6" 747 | "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.18.6" 748 | "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.18.9" 749 | "@babel/plugin-proposal-async-generator-functions" "^7.19.1" 750 | "@babel/plugin-proposal-class-properties" "^7.18.6" 751 | "@babel/plugin-proposal-class-static-block" "^7.18.6" 752 | "@babel/plugin-proposal-dynamic-import" "^7.18.6" 753 | "@babel/plugin-proposal-export-namespace-from" "^7.18.9" 754 | "@babel/plugin-proposal-json-strings" "^7.18.6" 755 | "@babel/plugin-proposal-logical-assignment-operators" "^7.18.9" 756 | "@babel/plugin-proposal-nullish-coalescing-operator" "^7.18.6" 757 | "@babel/plugin-proposal-numeric-separator" "^7.18.6" 758 | "@babel/plugin-proposal-object-rest-spread" "^7.19.4" 759 | "@babel/plugin-proposal-optional-catch-binding" "^7.18.6" 760 | "@babel/plugin-proposal-optional-chaining" "^7.18.9" 761 | "@babel/plugin-proposal-private-methods" "^7.18.6" 762 | "@babel/plugin-proposal-private-property-in-object" "^7.18.6" 763 | "@babel/plugin-proposal-unicode-property-regex" "^7.18.6" 764 | "@babel/plugin-syntax-async-generators" "^7.8.4" 765 | "@babel/plugin-syntax-class-properties" "^7.12.13" 766 | "@babel/plugin-syntax-class-static-block" "^7.14.5" 767 | "@babel/plugin-syntax-dynamic-import" "^7.8.3" 768 | "@babel/plugin-syntax-export-namespace-from" "^7.8.3" 769 | "@babel/plugin-syntax-import-assertions" "^7.18.6" 770 | "@babel/plugin-syntax-json-strings" "^7.8.3" 771 | "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" 772 | "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" 773 | "@babel/plugin-syntax-numeric-separator" "^7.10.4" 774 | "@babel/plugin-syntax-object-rest-spread" "^7.8.3" 775 | "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" 776 | "@babel/plugin-syntax-optional-chaining" "^7.8.3" 777 | "@babel/plugin-syntax-private-property-in-object" "^7.14.5" 778 | "@babel/plugin-syntax-top-level-await" "^7.14.5" 779 | "@babel/plugin-transform-arrow-functions" "^7.18.6" 780 | "@babel/plugin-transform-async-to-generator" "^7.18.6" 781 | "@babel/plugin-transform-block-scoped-functions" "^7.18.6" 782 | "@babel/plugin-transform-block-scoping" "^7.19.4" 783 | "@babel/plugin-transform-classes" "^7.19.0" 784 | "@babel/plugin-transform-computed-properties" "^7.18.9" 785 | "@babel/plugin-transform-destructuring" "^7.19.4" 786 | "@babel/plugin-transform-dotall-regex" "^7.18.6" 787 | "@babel/plugin-transform-duplicate-keys" "^7.18.9" 788 | "@babel/plugin-transform-exponentiation-operator" "^7.18.6" 789 | "@babel/plugin-transform-for-of" "^7.18.8" 790 | "@babel/plugin-transform-function-name" "^7.18.9" 791 | "@babel/plugin-transform-literals" "^7.18.9" 792 | "@babel/plugin-transform-member-expression-literals" "^7.18.6" 793 | "@babel/plugin-transform-modules-amd" "^7.18.6" 794 | "@babel/plugin-transform-modules-commonjs" "^7.18.6" 795 | "@babel/plugin-transform-modules-systemjs" "^7.19.0" 796 | "@babel/plugin-transform-modules-umd" "^7.18.6" 797 | "@babel/plugin-transform-named-capturing-groups-regex" "^7.19.1" 798 | "@babel/plugin-transform-new-target" "^7.18.6" 799 | "@babel/plugin-transform-object-super" "^7.18.6" 800 | "@babel/plugin-transform-parameters" "^7.18.8" 801 | "@babel/plugin-transform-property-literals" "^7.18.6" 802 | "@babel/plugin-transform-regenerator" "^7.18.6" 803 | "@babel/plugin-transform-reserved-words" "^7.18.6" 804 | "@babel/plugin-transform-shorthand-properties" "^7.18.6" 805 | "@babel/plugin-transform-spread" "^7.19.0" 806 | "@babel/plugin-transform-sticky-regex" "^7.18.6" 807 | "@babel/plugin-transform-template-literals" "^7.18.9" 808 | "@babel/plugin-transform-typeof-symbol" "^7.18.9" 809 | "@babel/plugin-transform-unicode-escapes" "^7.18.10" 810 | "@babel/plugin-transform-unicode-regex" "^7.18.6" 811 | "@babel/preset-modules" "^0.1.5" 812 | "@babel/types" "^7.19.4" 813 | babel-plugin-polyfill-corejs2 "^0.3.3" 814 | babel-plugin-polyfill-corejs3 "^0.6.0" 815 | babel-plugin-polyfill-regenerator "^0.4.1" 816 | core-js-compat "^3.25.1" 817 | semver "^6.3.0" 818 | 819 | "@babel/preset-modules@^0.1.5": 820 | version "0.1.5" 821 | resolved "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz" 822 | dependencies: 823 | "@babel/helper-plugin-utils" "^7.0.0" 824 | "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" 825 | "@babel/plugin-transform-dotall-regex" "^7.4.4" 826 | "@babel/types" "^7.4.4" 827 | esutils "^2.0.2" 828 | 829 | "@babel/preset-typescript@^7.14.5", "@babel/preset-typescript@^7.16.0": 830 | version "7.18.6" 831 | resolved "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz" 832 | dependencies: 833 | "@babel/helper-plugin-utils" "^7.18.6" 834 | "@babel/helper-validator-option" "^7.18.6" 835 | "@babel/plugin-transform-typescript" "^7.18.6" 836 | 837 | "@babel/runtime@^7.8.4": 838 | version "7.19.4" 839 | resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.4.tgz" 840 | dependencies: 841 | regenerator-runtime "^0.13.4" 842 | 843 | "@babel/template@^7.18.10": 844 | version "7.18.10" 845 | resolved "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz" 846 | dependencies: 847 | "@babel/code-frame" "^7.18.6" 848 | "@babel/parser" "^7.18.10" 849 | "@babel/types" "^7.18.10" 850 | 851 | "@babel/traverse@^7.19.0", "@babel/traverse@^7.19.1", "@babel/traverse@^7.19.3", "@babel/traverse@^7.19.4": 852 | version "7.19.4" 853 | resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.4.tgz" 854 | dependencies: 855 | "@babel/code-frame" "^7.18.6" 856 | "@babel/generator" "^7.19.4" 857 | "@babel/helper-environment-visitor" "^7.18.9" 858 | "@babel/helper-function-name" "^7.19.0" 859 | "@babel/helper-hoist-variables" "^7.18.6" 860 | "@babel/helper-split-export-declaration" "^7.18.6" 861 | "@babel/parser" "^7.19.4" 862 | "@babel/types" "^7.19.4" 863 | debug "^4.1.0" 864 | globals "^11.1.0" 865 | 866 | "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.19.3", "@babel/types@^7.19.4", "@babel/types@^7.4.4": 867 | version "7.19.4" 868 | resolved "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz" 869 | dependencies: 870 | "@babel/helper-string-parser" "^7.19.4" 871 | "@babel/helper-validator-identifier" "^7.19.1" 872 | to-fast-properties "^2.0.0" 873 | 874 | "@jridgewell/gen-mapping@^0.1.0": 875 | version "0.1.1" 876 | resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz" 877 | dependencies: 878 | "@jridgewell/set-array" "^1.0.0" 879 | "@jridgewell/sourcemap-codec" "^1.4.10" 880 | 881 | "@jridgewell/gen-mapping@^0.3.2": 882 | version "0.3.2" 883 | resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz" 884 | dependencies: 885 | "@jridgewell/set-array" "^1.0.1" 886 | "@jridgewell/sourcemap-codec" "^1.4.10" 887 | "@jridgewell/trace-mapping" "^0.3.9" 888 | 889 | "@jridgewell/resolve-uri@3.1.0": 890 | version "3.1.0" 891 | resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz" 892 | 893 | "@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": 894 | version "1.1.2" 895 | resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" 896 | 897 | "@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": 898 | version "1.4.14" 899 | resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" 900 | 901 | "@jridgewell/trace-mapping@^0.3.8", "@jridgewell/trace-mapping@^0.3.9": 902 | version "0.3.17" 903 | resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz" 904 | dependencies: 905 | "@jridgewell/resolve-uri" "3.1.0" 906 | "@jridgewell/sourcemap-codec" "1.4.14" 907 | 908 | "@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": 909 | version "2.1.8-no-fsevents.3" 910 | resolved "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz" 911 | 912 | ansi-styles@^3.2.1: 913 | version "3.2.1" 914 | resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" 915 | dependencies: 916 | color-convert "^1.9.0" 917 | 918 | anymatch@~3.1.2: 919 | version "3.1.2" 920 | resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz" 921 | dependencies: 922 | normalize-path "^3.0.0" 923 | picomatch "^2.0.4" 924 | 925 | axios-oauth-1.0a@^0.3.6: 926 | version "0.3.6" 927 | resolved "https://registry.npmjs.org/axios-oauth-1.0a/-/axios-oauth-1.0a-0.3.6.tgz" 928 | dependencies: 929 | oauth-sign "^0.9.0" 930 | 931 | babel-plugin-dynamic-import-node@^2.3.3: 932 | version "2.3.3" 933 | resolved "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz" 934 | dependencies: 935 | object.assign "^4.1.0" 936 | 937 | babel-plugin-polyfill-corejs2@^0.3.3: 938 | version "0.3.3" 939 | resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz" 940 | dependencies: 941 | "@babel/compat-data" "^7.17.7" 942 | "@babel/helper-define-polyfill-provider" "^0.3.3" 943 | semver "^6.1.1" 944 | 945 | babel-plugin-polyfill-corejs3@^0.6.0: 946 | version "0.6.0" 947 | resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz" 948 | dependencies: 949 | "@babel/helper-define-polyfill-provider" "^0.3.3" 950 | core-js-compat "^3.25.1" 951 | 952 | babel-plugin-polyfill-regenerator@^0.4.1: 953 | version "0.4.1" 954 | resolved "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz" 955 | dependencies: 956 | "@babel/helper-define-polyfill-provider" "^0.3.3" 957 | 958 | babel-plugin-transform-typescript-metadata@^0.3.1: 959 | version "0.3.2" 960 | resolved "https://registry.npmjs.org/babel-plugin-transform-typescript-metadata/-/babel-plugin-transform-typescript-metadata-0.3.2.tgz" 961 | dependencies: 962 | "@babel/helper-plugin-utils" "^7.0.0" 963 | 964 | babel-preset-medusa-package@^1.1.19: 965 | version "1.1.19" 966 | resolved "https://registry.npmjs.org/babel-preset-medusa-package/-/babel-preset-medusa-package-1.1.19.tgz" 967 | dependencies: 968 | "@babel/plugin-proposal-class-properties" "^7.12.1" 969 | "@babel/plugin-proposal-decorators" "^7.12.1" 970 | "@babel/plugin-proposal-optional-chaining" "^7.14.2" 971 | "@babel/plugin-transform-classes" "^7.12.1" 972 | "@babel/plugin-transform-instanceof" "^7.12.1" 973 | "@babel/plugin-transform-runtime" "^7.12.1" 974 | "@babel/preset-env" "^7.12.7" 975 | "@babel/preset-typescript" "^7.16.0" 976 | babel-plugin-transform-typescript-metadata "^0.3.1" 977 | core-js "^3.7.0" 978 | 979 | balanced-match@^1.0.0: 980 | version "1.0.2" 981 | resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" 982 | 983 | binary-extensions@^2.0.0: 984 | version "2.2.0" 985 | resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" 986 | 987 | brace-expansion@^1.1.7: 988 | version "1.1.11" 989 | resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" 990 | dependencies: 991 | balanced-match "^1.0.0" 992 | concat-map "0.0.1" 993 | 994 | braces@~3.0.2: 995 | version "3.0.2" 996 | resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" 997 | dependencies: 998 | fill-range "^7.0.1" 999 | 1000 | browserslist@^4.21.3, browserslist@^4.21.4: 1001 | version "4.21.4" 1002 | resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz" 1003 | dependencies: 1004 | caniuse-lite "^1.0.30001400" 1005 | electron-to-chromium "^1.4.251" 1006 | node-releases "^2.0.6" 1007 | update-browserslist-db "^1.0.9" 1008 | 1009 | call-bind@^1.0.2: 1010 | version "1.0.2" 1011 | resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz" 1012 | dependencies: 1013 | function-bind "^1.1.1" 1014 | get-intrinsic "^1.0.2" 1015 | 1016 | caniuse-lite@^1.0.30001400: 1017 | version "1.0.30001419" 1018 | resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001419.tgz" 1019 | 1020 | chalk@^2.0.0: 1021 | version "2.4.2" 1022 | resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" 1023 | dependencies: 1024 | ansi-styles "^3.2.1" 1025 | escape-string-regexp "^1.0.5" 1026 | supports-color "^5.3.0" 1027 | 1028 | chokidar@^3.4.0: 1029 | version "3.5.3" 1030 | resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" 1031 | dependencies: 1032 | anymatch "~3.1.2" 1033 | braces "~3.0.2" 1034 | glob-parent "~5.1.2" 1035 | is-binary-path "~2.1.0" 1036 | is-glob "~4.0.1" 1037 | normalize-path "~3.0.0" 1038 | readdirp "~3.6.0" 1039 | optionalDependencies: 1040 | fsevents "~2.3.2" 1041 | 1042 | color-convert@^1.9.0: 1043 | version "1.9.3" 1044 | resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" 1045 | dependencies: 1046 | color-name "1.1.3" 1047 | 1048 | color-name@1.1.3: 1049 | version "1.1.3" 1050 | resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" 1051 | 1052 | commander@^4.0.1: 1053 | version "4.1.1" 1054 | resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz" 1055 | 1056 | concat-map@0.0.1: 1057 | version "0.0.1" 1058 | resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" 1059 | 1060 | convert-source-map@^1.1.0, convert-source-map@^1.7.0: 1061 | version "1.9.0" 1062 | resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz" 1063 | 1064 | core-js-compat@^3.25.1: 1065 | version "3.25.5" 1066 | resolved "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.25.5.tgz" 1067 | dependencies: 1068 | browserslist "^4.21.4" 1069 | 1070 | core-js@^3.7.0: 1071 | version "3.25.5" 1072 | resolved "https://registry.npmjs.org/core-js/-/core-js-3.25.5.tgz" 1073 | 1074 | cross-env@^7.0.3: 1075 | version "7.0.3" 1076 | resolved "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz" 1077 | dependencies: 1078 | cross-spawn "^7.0.1" 1079 | 1080 | cross-spawn@^7.0.1: 1081 | version "7.0.3" 1082 | resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" 1083 | dependencies: 1084 | path-key "^3.1.0" 1085 | shebang-command "^2.0.0" 1086 | which "^2.0.1" 1087 | 1088 | debug@^4.1.0, debug@^4.1.1: 1089 | version "4.3.4" 1090 | resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" 1091 | dependencies: 1092 | ms "2.1.2" 1093 | 1094 | define-properties@^1.1.4: 1095 | version "1.1.4" 1096 | resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz" 1097 | dependencies: 1098 | has-property-descriptors "^1.0.0" 1099 | object-keys "^1.1.1" 1100 | 1101 | electron-to-chromium@^1.4.251: 1102 | version "1.4.282" 1103 | resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.282.tgz" 1104 | 1105 | escalade@^3.1.1: 1106 | version "3.1.1" 1107 | resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" 1108 | 1109 | escape-string-regexp@^1.0.5: 1110 | version "1.0.5" 1111 | resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" 1112 | 1113 | esutils@^2.0.2: 1114 | version "2.0.3" 1115 | resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" 1116 | 1117 | fill-range@^7.0.1: 1118 | version "7.0.1" 1119 | resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" 1120 | dependencies: 1121 | to-regex-range "^5.0.1" 1122 | 1123 | fs-readdir-recursive@^1.1.0: 1124 | version "1.1.0" 1125 | resolved "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz" 1126 | 1127 | fs.realpath@^1.0.0: 1128 | version "1.0.0" 1129 | resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" 1130 | 1131 | fsevents@~2.3.2: 1132 | version "2.3.2" 1133 | resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" 1134 | 1135 | function-bind@^1.1.1: 1136 | version "1.1.1" 1137 | resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" 1138 | 1139 | gensync@^1.0.0-beta.2: 1140 | version "1.0.0-beta.2" 1141 | resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" 1142 | 1143 | get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: 1144 | version "1.1.3" 1145 | resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz" 1146 | dependencies: 1147 | function-bind "^1.1.1" 1148 | has "^1.0.3" 1149 | has-symbols "^1.0.3" 1150 | 1151 | glob-parent@~5.1.2: 1152 | version "5.1.2" 1153 | resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" 1154 | dependencies: 1155 | is-glob "^4.0.1" 1156 | 1157 | glob@^7.2.0: 1158 | version "7.2.3" 1159 | resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" 1160 | dependencies: 1161 | fs.realpath "^1.0.0" 1162 | inflight "^1.0.4" 1163 | inherits "2" 1164 | minimatch "^3.1.1" 1165 | once "^1.3.0" 1166 | path-is-absolute "^1.0.0" 1167 | 1168 | globals@^11.1.0: 1169 | version "11.12.0" 1170 | resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" 1171 | 1172 | has-flag@^3.0.0: 1173 | version "3.0.0" 1174 | resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" 1175 | 1176 | has-property-descriptors@^1.0.0: 1177 | version "1.0.0" 1178 | resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz" 1179 | dependencies: 1180 | get-intrinsic "^1.1.1" 1181 | 1182 | has-symbols@^1.0.3: 1183 | version "1.0.3" 1184 | resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" 1185 | 1186 | has@^1.0.3: 1187 | version "1.0.3" 1188 | resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" 1189 | dependencies: 1190 | function-bind "^1.1.1" 1191 | 1192 | inflight@^1.0.4: 1193 | version "1.0.6" 1194 | resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" 1195 | dependencies: 1196 | once "^1.3.0" 1197 | wrappy "1" 1198 | 1199 | inherits@2: 1200 | version "2.0.4" 1201 | resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" 1202 | 1203 | is-binary-path@~2.1.0: 1204 | version "2.1.0" 1205 | resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" 1206 | dependencies: 1207 | binary-extensions "^2.0.0" 1208 | 1209 | is-core-module@^2.9.0: 1210 | version "2.10.0" 1211 | resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz" 1212 | dependencies: 1213 | has "^1.0.3" 1214 | 1215 | is-extglob@^2.1.1: 1216 | version "2.1.1" 1217 | resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" 1218 | 1219 | is-glob@^4.0.1, is-glob@~4.0.1: 1220 | version "4.0.3" 1221 | resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" 1222 | dependencies: 1223 | is-extglob "^2.1.1" 1224 | 1225 | is-number@^7.0.0: 1226 | version "7.0.0" 1227 | resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" 1228 | 1229 | isexe@^2.0.0: 1230 | version "2.0.0" 1231 | resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" 1232 | 1233 | js-tokens@^4.0.0: 1234 | version "4.0.0" 1235 | resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" 1236 | 1237 | jsesc@^2.5.1: 1238 | version "2.5.2" 1239 | resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" 1240 | 1241 | jsesc@~0.5.0: 1242 | version "0.5.0" 1243 | resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz" 1244 | 1245 | json5@^2.2.1: 1246 | version "2.2.3" 1247 | resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" 1248 | 1249 | lodash.debounce@^4.0.8: 1250 | version "4.0.8" 1251 | resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz" 1252 | 1253 | make-dir@^2.1.0: 1254 | version "2.1.0" 1255 | resolved "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz" 1256 | dependencies: 1257 | pify "^4.0.1" 1258 | semver "^5.6.0" 1259 | 1260 | minimatch@^3.1.1: 1261 | version "3.1.2" 1262 | resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" 1263 | dependencies: 1264 | brace-expansion "^1.1.7" 1265 | 1266 | ms@2.1.2: 1267 | version "2.1.2" 1268 | resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" 1269 | 1270 | node-releases@^2.0.6: 1271 | version "2.0.6" 1272 | resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz" 1273 | 1274 | normalize-path@^3.0.0, normalize-path@~3.0.0: 1275 | version "3.0.0" 1276 | resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" 1277 | 1278 | oauth-sign@^0.9.0: 1279 | version "0.9.0" 1280 | resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz" 1281 | 1282 | object-keys@^1.1.1: 1283 | version "1.1.1" 1284 | resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" 1285 | 1286 | object.assign@^4.1.0: 1287 | version "4.1.4" 1288 | resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz" 1289 | dependencies: 1290 | call-bind "^1.0.2" 1291 | define-properties "^1.1.4" 1292 | has-symbols "^1.0.3" 1293 | object-keys "^1.1.1" 1294 | 1295 | once@^1.3.0: 1296 | version "1.4.0" 1297 | resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" 1298 | dependencies: 1299 | wrappy "1" 1300 | 1301 | path-is-absolute@^1.0.0: 1302 | version "1.0.1" 1303 | resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" 1304 | 1305 | path-key@^3.1.0: 1306 | version "3.1.1" 1307 | resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" 1308 | 1309 | path-parse@^1.0.7: 1310 | version "1.0.7" 1311 | resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" 1312 | 1313 | picocolors@^1.0.0: 1314 | version "1.0.0" 1315 | resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" 1316 | 1317 | picomatch@^2.0.4, picomatch@^2.2.1: 1318 | version "2.3.1" 1319 | resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" 1320 | 1321 | pify@^4.0.1: 1322 | version "4.0.1" 1323 | resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz" 1324 | 1325 | readdirp@~3.6.0: 1326 | version "3.6.0" 1327 | resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" 1328 | dependencies: 1329 | picomatch "^2.2.1" 1330 | 1331 | regenerate-unicode-properties@^10.1.0: 1332 | version "10.1.0" 1333 | resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz" 1334 | dependencies: 1335 | regenerate "^1.4.2" 1336 | 1337 | regenerate@^1.4.2: 1338 | version "1.4.2" 1339 | resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz" 1340 | 1341 | regenerator-runtime@^0.13.4: 1342 | version "0.13.10" 1343 | resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz" 1344 | 1345 | regenerator-transform@^0.15.0: 1346 | version "0.15.0" 1347 | resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz" 1348 | dependencies: 1349 | "@babel/runtime" "^7.8.4" 1350 | 1351 | regexpu-core@^5.1.0: 1352 | version "5.2.1" 1353 | resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz" 1354 | dependencies: 1355 | regenerate "^1.4.2" 1356 | regenerate-unicode-properties "^10.1.0" 1357 | regjsgen "^0.7.1" 1358 | regjsparser "^0.9.1" 1359 | unicode-match-property-ecmascript "^2.0.0" 1360 | unicode-match-property-value-ecmascript "^2.0.0" 1361 | 1362 | regjsgen@^0.7.1: 1363 | version "0.7.1" 1364 | resolved "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz" 1365 | 1366 | regjsparser@^0.9.1: 1367 | version "0.9.1" 1368 | resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz" 1369 | dependencies: 1370 | jsesc "~0.5.0" 1371 | 1372 | resolve@^1.14.2: 1373 | version "1.22.1" 1374 | resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz" 1375 | dependencies: 1376 | is-core-module "^2.9.0" 1377 | path-parse "^1.0.7" 1378 | supports-preserve-symlinks-flag "^1.0.0" 1379 | 1380 | semver@^5.6.0: 1381 | version "5.7.1" 1382 | resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" 1383 | 1384 | semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: 1385 | version "6.3.0" 1386 | resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" 1387 | 1388 | shebang-command@^2.0.0: 1389 | version "2.0.0" 1390 | resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" 1391 | dependencies: 1392 | shebang-regex "^3.0.0" 1393 | 1394 | shebang-regex@^3.0.0: 1395 | version "3.0.0" 1396 | resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" 1397 | 1398 | slash@^2.0.0: 1399 | version "2.0.0" 1400 | resolved "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz" 1401 | 1402 | supports-color@^5.3.0: 1403 | version "5.5.0" 1404 | resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" 1405 | dependencies: 1406 | has-flag "^3.0.0" 1407 | 1408 | supports-preserve-symlinks-flag@^1.0.0: 1409 | version "1.0.0" 1410 | resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" 1411 | 1412 | to-fast-properties@^2.0.0: 1413 | version "2.0.0" 1414 | resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" 1415 | 1416 | to-regex-range@^5.0.1: 1417 | version "5.0.1" 1418 | resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" 1419 | dependencies: 1420 | is-number "^7.0.0" 1421 | 1422 | unicode-canonical-property-names-ecmascript@^2.0.0: 1423 | version "2.0.0" 1424 | resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz" 1425 | 1426 | unicode-match-property-ecmascript@^2.0.0: 1427 | version "2.0.0" 1428 | resolved "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz" 1429 | dependencies: 1430 | unicode-canonical-property-names-ecmascript "^2.0.0" 1431 | unicode-property-aliases-ecmascript "^2.0.0" 1432 | 1433 | unicode-match-property-value-ecmascript@^2.0.0: 1434 | version "2.0.0" 1435 | resolved "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz" 1436 | 1437 | unicode-property-aliases-ecmascript@^2.0.0: 1438 | version "2.1.0" 1439 | resolved "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz" 1440 | 1441 | update-browserslist-db@^1.0.9: 1442 | version "1.0.10" 1443 | resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz" 1444 | dependencies: 1445 | escalade "^3.1.1" 1446 | picocolors "^1.0.0" 1447 | 1448 | which@^2.0.1: 1449 | version "2.0.2" 1450 | resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" 1451 | dependencies: 1452 | isexe "^2.0.0" 1453 | 1454 | wrappy@1: 1455 | version "1.0.2" 1456 | resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" 1457 | --------------------------------------------------------------------------------