diff --git a/.eslintrc.json b/.eslintrc.json index abf36bc..0c665fb 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -50,13 +50,16 @@ "error", { "accessibility": "no-public" } - ] + ], + "no-return-await": "off", + "@typescript-eslint/return-await": "error" }, "ignorePatterns": [ "**/*.js", "**/*.mjs", "**/*.cjs", "dist", + "out", "azure-functions-language-worker-protobuf" ] } \ No newline at end of file diff --git a/.gitignore b/.gitignore index 4ac8545..96f4756 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ jspm_packages azure-functions-language-worker-protobuf/* dist +out pkg *.tgz diff --git a/.vscode/tasks.json b/.vscode/tasks.json index e87e663..4b8de04 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -9,7 +9,7 @@ "kind": "build", "isDefault": true }, - "problemMatcher": "$tsc-watch", + "problemMatcher": ["$ts-checker-webpack-watch"], "isBackground": true, "presentation": { "reveal": "never" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..6ace4d4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,25 @@ +# Contributing + +- Clone the repository locally and open in VS Code +- Run "Extensions: Show Recommended Extensions" from the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) and install all extensions listed under "Workspace Recommendations" +- Run `npm install` +- Run `npm run build` +- Run `npm link` +- Create or open a local function app to test with +- In the local function app: + - Make sure you are calling `func.setup()` somewhere in your app, as described above in the "Usage" section + - Run `npm link @azure/functions`. This will point your app to the local repository for the `@azure/functions` package + - Add the following settings to your "local.settings.json" file or configure them directly as environment variables + - `languageWorkers__node__arguments`: `--inspect` + > 💡 Tip: Set `logging__logLevel__Worker` to `debug` if you want to view worker-specific logs in the output of `func start` + - Start the app (i.e. run `func start` or press F5) +- Back in the framework repository, press F5 and select the process for your running function app +- Before you submit a PR, run `npm test` and fix any issues. If you want to debug the tests, switch your [launch profile](https://code.visualstudio.com/docs/editor/debugging) in VS Code to "Launch Unit Tests" and press F5. + +## Code of Conduct + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + +## Contributing to type definitions + +The type definitions are located in the `types` folder. Please make sure to update the tests in `./test/types/index.test.ts` as well. diff --git a/NOTICE.html b/NOTICE.html deleted file mode 100644 index e2b321b..0000000 --- a/NOTICE.html +++ /dev/null @@ -1,389 +0,0 @@ - - - - NOTICES AND INFORMATION - - - -

NOTICES AND INFORMATION

-

Do Not Translate or Localize

-

- This software incorporates material from third parties. - Microsoft makes certain open source code available at https://3rdpartysource.microsoft.com, - or you may send a check or money order for US $5.00, including the product name, - the open source component name, platform, and version number, to: -

-
- Source Code Compliance Team
- Microsoft Corporation
- One Microsoft Way
- Redmond, WA 98052
- USA -
-

- Notwithstanding any other terms, you may reverse engineer this software to the extent - required to debug changes to any libraries licensed under the GNU Lesser General Public License. -

-
    -
  1. -
    - - long 4.0.0 - Apache-2.0 - -

    https://github.com/dcodeIO/long.js#readme

    - -
    -        
    -                                 Apache License
    -                           Version 2.0, January 2004
    -                        http://www.apache.org/licenses/
    -
    -   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
    -
    -   1. Definitions.
    -
    -      "License" shall mean the terms and conditions for use, reproduction,
    -      and distribution as defined by Sections 1 through 9 of this document.
    -
    -      "Licensor" shall mean the copyright owner or entity authorized by
    -      the copyright owner that is granting the License.
    -
    -      "Legal Entity" shall mean the union of the acting entity and all
    -      other entities that control, are controlled by, or are under common
    -      control with that entity. For the purposes of this definition,
    -      "control" means (i) the power, direct or indirect, to cause the
    -      direction or management of such entity, whether by contract or
    -      otherwise, or (ii) ownership of fifty percent (50%) or more of the
    -      outstanding shares, or (iii) beneficial ownership of such entity.
    -
    -      "You" (or "Your") shall mean an individual or Legal Entity
    -      exercising permissions granted by this License.
    -
    -      "Source" form shall mean the preferred form for making modifications,
    -      including but not limited to software source code, documentation
    -      source, and configuration files.
    -
    -      "Object" form shall mean any form resulting from mechanical
    -      transformation or translation of a Source form, including but
    -      not limited to compiled object code, generated documentation,
    -      and conversions to other media types.
    -
    -      "Work" shall mean the work of authorship, whether in Source or
    -      Object form, made available under the License, as indicated by a
    -      copyright notice that is included in or attached to the work
    -      (an example is provided in the Appendix below).
    -
    -      "Derivative Works" shall mean any work, whether in Source or Object
    -      form, that is based on (or derived from) the Work and for which the
    -      editorial revisions, annotations, elaborations, or other modifications
    -      represent, as a whole, an original work of authorship. For the purposes
    -      of this License, Derivative Works shall not include works that remain
    -      separable from, or merely link (or bind by name) to the interfaces of,
    -      the Work and Derivative Works thereof.
    -
    -      "Contribution" shall mean any work of authorship, including
    -      the original version of the Work and any modifications or additions
    -      to that Work or Derivative Works thereof, that is intentionally
    -      submitted to Licensor for inclusion in the Work by the copyright owner
    -      or by an individual or Legal Entity authorized to submit on behalf of
    -      the copyright owner. For the purposes of this definition, "submitted"
    -      means any form of electronic, verbal, or written communication sent
    -      to the Licensor or its representatives, including but not limited to
    -      communication on electronic mailing lists, source code control systems,
    -      and issue tracking systems that are managed by, or on behalf of, the
    -      Licensor for the purpose of discussing and improving the Work, but
    -      excluding communication that is conspicuously marked or otherwise
    -      designated in writing by the copyright owner as "Not a Contribution."
    -
    -      "Contributor" shall mean Licensor and any individual or Legal Entity
    -      on behalf of whom a Contribution has been received by Licensor and
    -      subsequently incorporated within the Work.
    -
    -   2. Grant of Copyright License. Subject to the terms and conditions of
    -      this License, each Contributor hereby grants to You a perpetual,
    -      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
    -      copyright license to reproduce, prepare Derivative Works of,
    -      publicly display, publicly perform, sublicense, and distribute the
    -      Work and such Derivative Works in Source or Object form.
    -
    -   3. Grant of Patent License. Subject to the terms and conditions of
    -      this License, each Contributor hereby grants to You a perpetual,
    -      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
    -      (except as stated in this section) patent license to make, have made,
    -      use, offer to sell, sell, import, and otherwise transfer the Work,
    -      where such license applies only to those patent claims licensable
    -      by such Contributor that are necessarily infringed by their
    -      Contribution(s) alone or by combination of their Contribution(s)
    -      with the Work to which such Contribution(s) was submitted. If You
    -      institute patent litigation against any entity (including a
    -      cross-claim or counterclaim in a lawsuit) alleging that the Work
    -      or a Contribution incorporated within the Work constitutes direct
    -      or contributory patent infringement, then any patent licenses
    -      granted to You under this License for that Work shall terminate
    -      as of the date such litigation is filed.
    -
    -   4. Redistribution. You may reproduce and distribute copies of the
    -      Work or Derivative Works thereof in any medium, with or without
    -      modifications, and in Source or Object form, provided that You
    -      meet the following conditions:
    -
    -      (a) You must give any other recipients of the Work or
    -          Derivative Works a copy of this License; and
    -
    -      (b) You must cause any modified files to carry prominent notices
    -          stating that You changed the files; and
    -
    -      (c) You must retain, in the Source form of any Derivative Works
    -          that You distribute, all copyright, patent, trademark, and
    -          attribution notices from the Source form of the Work,
    -          excluding those notices that do not pertain to any part of
    -          the Derivative Works; and
    -
    -      (d) If the Work includes a "NOTICE" text file as part of its
    -          distribution, then any Derivative Works that You distribute must
    -          include a readable copy of the attribution notices contained
    -          within such NOTICE file, excluding those notices that do not
    -          pertain to any part of the Derivative Works, in at least one
    -          of the following places: within a NOTICE text file distributed
    -          as part of the Derivative Works; within the Source form or
    -          documentation, if provided along with the Derivative Works; or,
    -          within a display generated by the Derivative Works, if and
    -          wherever such third-party notices normally appear. The contents
    -          of the NOTICE file are for informational purposes only and
    -          do not modify the License. You may add Your own attribution
    -          notices within Derivative Works that You distribute, alongside
    -          or as an addendum to the NOTICE text from the Work, provided
    -          that such additional attribution notices cannot be construed
    -          as modifying the License.
    -
    -      You may add Your own copyright statement to Your modifications and
    -      may provide additional or different license terms and conditions
    -      for use, reproduction, or distribution of Your modifications, or
    -      for any such Derivative Works as a whole, provided Your use,
    -      reproduction, and distribution of the Work otherwise complies with
    -      the conditions stated in this License.
    -
    -   5. Submission of Contributions. Unless You explicitly state otherwise,
    -      any Contribution intentionally submitted for inclusion in the Work
    -      by You to the Licensor shall be under the terms and conditions of
    -      this License, without any additional terms or conditions.
    -      Notwithstanding the above, nothing herein shall supersede or modify
    -      the terms of any separate license agreement you may have executed
    -      with Licensor regarding such Contributions.
    -
    -   6. Trademarks. This License does not grant permission to use the trade
    -      names, trademarks, service marks, or product names of the Licensor,
    -      except as required for reasonable and customary use in describing the
    -      origin of the Work and reproducing the content of the NOTICE file.
    -
    -   7. Disclaimer of Warranty. Unless required by applicable law or
    -      agreed to in writing, Licensor provides the Work (and each
    -      Contributor provides its Contributions) on an "AS IS" BASIS,
    -      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    -      implied, including, without limitation, any warranties or conditions
    -      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
    -      PARTICULAR PURPOSE. You are solely responsible for determining the
    -      appropriateness of using or redistributing the Work and assume any
    -      risks associated with Your exercise of permissions under this License.
    -
    -   8. Limitation of Liability. In no event and under no legal theory,
    -      whether in tort (including negligence), contract, or otherwise,
    -      unless required by applicable law (such as deliberate and grossly
    -      negligent acts) or agreed to in writing, shall any Contributor be
    -      liable to You for damages, including any direct, indirect, special,
    -      incidental, or consequential damages of any character arising as a
    -      result of this License or out of the use or inability to use the
    -      Work (including but not limited to damages for loss of goodwill,
    -      work stoppage, computer failure or malfunction, or any and all
    -      other commercial damages or losses), even if such Contributor
    -      has been advised of the possibility of such damages.
    -
    -   9. Accepting Warranty or Additional Liability. While redistributing
    -      the Work or Derivative Works thereof, You may choose to offer,
    -      and charge a fee for, acceptance of support, warranty, indemnity,
    -      or other liability obligations and/or rights consistent with this
    -      License. However, in accepting such obligations, You may act only
    -      on Your own behalf and on Your sole responsibility, not on behalf
    -      of any other Contributor, and only if You agree to indemnify,
    -      defend, and hold each Contributor harmless for any liability
    -      incurred by, or claims asserted against, such Contributor by reason
    -      of your accepting any such warranty or additional liability.
    -
    -   END OF TERMS AND CONDITIONS
    -
    -   APPENDIX: How to apply the Apache License to your work.
    -
    -      To apply the Apache License to your work, attach the following
    -      boilerplate notice, with the fields enclosed by brackets "[]"
    -      replaced with your own identifying information. (Don't include
    -      the brackets!)  The text should be enclosed in the appropriate
    -      comment syntax for the file format. We also recommend that a
    -      file or class name and description of purpose be included on the
    -      same "printed page" as the copyright notice for easier
    -      identification within third-party archives.
    -
    -   Copyright [yyyy] [name of copyright owner]
    -
    -   Licensed under the Apache License, Version 2.0 (the "License");
    -   you may not use this file except in compliance with the License.
    -   You may obtain a copy of the License at
    -
    -       http://www.apache.org/licenses/LICENSE-2.0
    -
    -   Unless required by applicable law or agreed to in writing, software
    -   distributed under the License is distributed on an "AS IS" BASIS,
    -   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    -   See the License for the specific language governing permissions and
    -   limitations under the License.
    -
    -        
    -
    -
  2. -
  3. -
    - - graceful-fs 4.2.10 - ISC - -

    https://github.com/isaacs/node-graceful-fs#readme

    -
    • Copyright (c) 2011-2022 Isaac Z. Schlueter, Ben Noordhuis, and Contributors
    -
    -        The ISC License
    -
    -Copyright (c) 2011-2022 Isaac Z. Schlueter, Ben Noordhuis, and Contributors
    -
    -Permission to use, copy, modify, and/or distribute this software for any
    -purpose with or without fee is hereby granted, provided that the above
    -copyright notice and this permission notice appear in all copies.
    -
    -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
    -IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    -
    -        
    -
    -
  4. -
  5. -
    - - fs-extra 10.0.1 - MIT - -

    https://github.com/jprichardson/node-fs-extra

    -
    • Copyright (c) 2011-2017 JP Richardson
    • -
    • Copyright (c) 2011-2017 JP Richardson (https://github.com/jprichardson)
    • -
    • Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
    • -
    • Copyright (c) 2014-2016 Jonathan Ong me@jongleberry.com and Contributors
    -
    -        (The MIT License)
    -
    -Copyright (c) 2011-2017 JP Richardson
    -
    -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
    -(the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
    - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
    - furnished to do so, subject to the following conditions:
    -
    -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
    -
    -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
    -WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
    -OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
    - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    -
    -        
    -
    -
  6. -
  7. -
    - - jsonfile 6.1.0 - MIT - -

    https://github.com/jprichardson/node-jsonfile#readme

    -
    • Copyright 2012-2016, JP Richardson <jprichardson@gmail.com>
    • -
    • Copyright (c) 2012-2015, JP Richardson <jprichardson@gmail.com>
    -
    -        (The MIT License)
    -
    -Copyright (c) 2012-2015, JP Richardson <jprichardson@gmail.com>
    -
    -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
    -(the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
    - merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
    - furnished to do so, subject to the following conditions:
    -
    -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
    -
    -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
    -WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
    -OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
    - ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    -
    -        
    -
    -
  8. -
  9. -
    - - universalify 2.0.0 - MIT - -

    https://github.com/RyanZim/universalify#readme

    -
    • Copyright (c) 2017, Ryan Zimmerman <opensrc@ryanzim.com>
    -
    -        (The MIT License)
    -
    -Copyright (c) 2017, Ryan Zimmerman <opensrc@ryanzim.com>
    -
    -Permission is hereby granted, free of charge, to any person obtaining a copy of
    -this software and associated documentation files (the 'Software'), to deal in
    -the Software without restriction, including without limitation the rights to
    -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
    -the Software, and to permit persons to whom the Software is furnished to do so,
    -subject to the following conditions:
    -
    -The above copyright notice and this permission notice shall be included in all
    -copies or substantial portions of the Software.
    -
    -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
    -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
    -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
    -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
    -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    -
    -        
    -
    -
  10. -
  11. -
    - - uuid 8.3.0 - MIT - -

    https://github.com/uuidjs/uuid#readme

    -
    • Copyright 2011, Sebastian Tschan https://blueimp.net
    • -
    • Copyright (c) Paul Johnston 1999 - 2009 Other contributors Greg Holt, Andrew Kepert, Ydnar, Lostinet
    -
    -        The MIT License (MIT)
    -
    -Copyright (c) 2010-2020 Robert Kieffer and other contributors
    -
    -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
    -
    -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
    -
    -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    -
    -        
    -
    -
  12. -
- - \ No newline at end of file diff --git a/README.md b/README.md index 6f3ff37..ad9bccb 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,43 @@ -# Azure Functions Node.js Framework +# Azure Functions Node.js Programming Model |Branch|Status|Support level|Node.js Versions| |---|---|---|---| -|v4.x|[![Build Status](https://img.shields.io/azure-devops/build/azfunc/Azure%2520Functions/145/v4.x)](https://azfunc.visualstudio.com/Azure%20Functions/_build/latest?definitionId=145&branchName=v4.x) [![Test Status](https://img.shields.io/azure-devops/tests/azfunc/Azure%2520Functions/146/v4.x?compact_message)](https://azfunc.visualstudio.com/Azure%20Functions/_build/latest?definitionId=146&branchName=v4.x)|Preview|18 (preview)| -|v3.x (default)|[![Build Status](https://img.shields.io/azure-devops/build/azfunc/Azure%2520Functions/145/v3.x)](https://azfunc.visualstudio.com/Azure%20Functions/_build/latest?definitionId=145&branchName=v3.x) [![Test Status](https://img.shields.io/azure-devops/tests/azfunc/Azure%2520Functions/146/v3.x?compact_message)](https://azfunc.visualstudio.com/Azure%20Functions/_build/latest?definitionId=146&branchName=v3.x)|GA (Recommended)|18 (preview), 16, 14| +|v3.x|[![Build Status](https://img.shields.io/azure-devops/build/azfunc/public/514/v3.x)](https://azfunc.visualstudio.com/public/_build/latest?definitionId=514&branchName=v3.x) [![Test Status](https://img.shields.io/azure-devops/tests/azfunc/public/514/v3.x?compact_message)](https://azfunc.visualstudio.com/public/_build/latest?definitionId=514&branchName=v3.x)|GA|20, 18| ## Install -``` -npm install @azure/functions +```bash +npm install @azure/functions@3 ``` -## Usage +## Documentation + +- [Azure Functions JavaScript Developer Guide](https://learn.microsoft.com/azure/azure-functions/functions-reference-node?pivots=nodejs-model-v3) +- [Create your first TypeScript function](https://docs.microsoft.com/azure/azure-functions/create-first-function-vs-code-typescript?pivots=nodejs-model-v3) +- [Create your first JavaScript function](https://docs.microsoft.com/azure/azure-functions/create-first-function-vs-code-node?pivots=nodejs-model-v3) -Prior to version 3.5.0, this package only contained TypeScript type definitions. Starting with version 3.5.0 it _also_ contains the underlying Azure Functions Framework for Node.js. This framework package is included by default in [v4.x of the Azure Functions runtime](https://docs.microsoft.com/azure/azure-functions/functions-versions?pivots=programming-language-javascript), meaning you do _not_ need to include the package in your app. However, there may be cases where you want a specific version of the package, so you can override the default shipped in Azure with the below steps. +## Considerations + +- The Node.js "programming model" shouldn't be confused with the Azure Functions "runtime". + - _**Programming model**_: Defines how you author your code and is specific to JavaScript and TypeScript. + - _**Runtime**_: Defines underlying behavior of Azure Functions and is shared across all languages. +- The programming model version is strictly tied to the version of the [`@azure/functions`](https://www.npmjs.com/package/@azure/functions) npm package, and is versioned independently of the [runtime](https://learn.microsoft.com/azure/azure-functions/functions-versions?pivots=programming-language-javascript). Both the runtime and the programming model use "4" as their latest major version, but that is purely a coincidence. +- You can't mix the v3 and v4 programming models in the same function app. As soon as you register one v4 function in your app, any v3 functions registered in _function.json_ files are ignored. + +## Usage -### TypeScript: +Prior to version 3.5.0, this package only contained TypeScript type definitions. Starting with version 3.5.0 it _also_ contains the underlying Azure Functions Programming Model for Node.js. This package is included by default in [v4.x of the Azure Functions runtime](https://docs.microsoft.com/azure/azure-functions/functions-versions?pivots=programming-language-javascript), meaning you do _not_ need to include the package in your app. However, there may be cases where you want a specific version of the package, so you can override the default shipped in Azure with the below steps. -For a full tutorial, see [how to create your first TypeScript function](https://docs.microsoft.com/azure/azure-functions/create-first-function-vs-code-typescript). +### TypeScript 1. Specify a main entrypoint in your package.json + ```json "main": "dist/src/index.js" ``` + 2. Add the following code to your entrypoint file (e.g. `src/index.ts`): + ```typescript import * as func from '@azure/functions'; @@ -32,47 +46,18 @@ For a full tutorial, see [how to create your first TypeScript function](https:// **IMPORTANT NOTE**: If you only want this package for the TypeScript type definitions, you may list this package in the "devDependencies" section of your package.json. If you are overriding the default shipped in Azure as described above, the package must be listed in the production "dependencies" section of your package.json. -For more documentation, see the [TypeScript developer guide](https://docs.microsoft.com/azure/azure-functions/functions-reference-node#typescript). - ### JavaScript -For a full tutorial, see [how to create your first JavaScript function](https://docs.microsoft.com/azure/azure-functions/create-first-function-vs-code-node). - 1. Specify a main entrypoint in your package.json + ```json "main": "src/index.js" ``` + 2. Add the following code to your entrypoint file: + ```javascript const func = require('@azure/functions'); func.setup(); ``` - -For more documentation, see the [JavaScript developer guide](https://docs.microsoft.com/azure/azure-functions/functions-reference-node). - -## Contributing - -- Clone the repository locally and open in VS Code -- Run "Extensions: Show Recommended Extensions" from the [command palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette) and install all extensions listed under "Workspace Recommendations" -- Run `npm install` -- Run `npm run build` -- Run `npm link` -- Create or open a local function app to test with -- In the local function app: - - Make sure you are calling `func.setup()` somewhere in your app, as described above in the "Usage" section - - Run `npm link @azure/functions`. This will point your app to the local repository for the framework package - - Add the following settings to your "local.settings.json" file or configure them directly as environment variables - - `languageWorkers__node__arguments`: `--inspect` - > 💡 Tip: Set `logging__logLevel__Worker` to `debug` if you want to view worker-specific logs in the output of `func start` - - Start the app (i.e. run `func start` or press F5) -- Back in the framework repository, press F5 and select the process for your running function app -- Before you submit a PR, run `npm run lint` and `npm test` and fix any issues. If you want to debug the tests, switch your [launch profile](https://code.visualstudio.com/docs/editor/debugging) in VS Code to "Launch Unit Tests" and press F5. - -### Code of Conduct - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. - -### Contributing to type definitions - -The type definitions are located in the `types` folder. Any changes should be applied directly to `./types/index.d.ts`. Please make sure to update the tests in `./types/index.test.ts` as well. \ No newline at end of file diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml deleted file mode 100644 index 8f87761..0000000 --- a/azure-pipelines/build.yml +++ /dev/null @@ -1,64 +0,0 @@ -pr: - branches: - include: - - v3.x - -trigger: -- v3.x - -jobs: -- job: BuildArtifacts - pool: - name: '1ES-Hosted-AzFunc' - demands: - - ImageOverride -equals MMS2019TLS - steps: - - task: NodeTool@0 - inputs: - versionSpec: 14.x - displayName: 'Install Node.js' - - script: npm ci - displayName: 'npm ci' - - script: npm run build - displayName: 'npm run build' - - script: npm run webpack - displayName: 'npm run webpack' - - task: CopyFiles@2 - displayName: 'Copy files to staging' - inputs: - sourceFolder: '$(Build.SourcesDirectory)' - contents: | - dist/src/index-bundle.js - types/index.d.ts - LICENSE - NOTICE.html - package.json - README.md - targetFolder: '$(Build.ArtifactStagingDirectory)' - cleanTargetFolder: true - - script: npm prune --production - displayName: 'npm prune --production' # so that only production dependencies are included in SBOM - - task: ManifestGeneratorTask@0 - displayName: 'Generate SBOM' - inputs: - BuildDropPath: '$(Build.ArtifactStagingDirectory)' - # The list of components can't be determined from the webpacked file in the staging dir, so reference the original node_modules folder - BuildComponentPath: '$(Build.SourcesDirectory)/node_modules' - PackageName: 'Azure Functions Node.js Framework' - - script: npm pack - displayName: 'npm pack' - workingDirectory: '$(Build.ArtifactStagingDirectory)' - - task: CopyFiles@2 - displayName: 'Copy package to staging drop folder' - inputs: - sourceFolder: '$(Build.ArtifactStagingDirectory)' - contents: | - *.tgz - targetFolder: '$(Build.ArtifactStagingDirectory)/drop' - cleanTargetFolder: true - - task: PublishPipelineArtifact@1 - displayName: 'Publish drop' - inputs: - targetPath: '$(Build.ArtifactStagingDirectory)/drop' - artifact: 'drop' - publishLocation: 'pipeline' diff --git a/azure-pipelines/code-mirror.yml b/azure-pipelines/code-mirror.yml new file mode 100644 index 0000000..0f1804a --- /dev/null +++ b/azure-pipelines/code-mirror.yml @@ -0,0 +1,17 @@ +trigger: + branches: + include: + - v*.x + +resources: + repositories: + - repository: eng + type: git + name: engineering + ref: refs/tags/release + +variables: + - template: ci/variables/cfs.yml@eng + +extends: + template: ci/code-mirror.yml@eng diff --git a/azure-pipelines/official-build.yml b/azure-pipelines/official-build.yml new file mode 100644 index 0000000..7deb330 --- /dev/null +++ b/azure-pipelines/official-build.yml @@ -0,0 +1,58 @@ +parameters: + - name: IsPrerelease + type: boolean + default: true + +trigger: + batch: true + branches: + include: + - v3.x + +# CI only, does not trigger on PRs. +pr: none + +schedules: + - cron: '30 10 * * *' + displayName: Nightly build + always: true + branches: + include: + - v3.x + +resources: + repositories: + - repository: 1es + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + +extends: + template: v1/1ES.Official.PipelineTemplate.yml@1es + parameters: + pool: + name: 1es-pool-azfunc + image: 1es-windows-2022 + os: windows + + stages: + - stage: WindowsUnitTests + dependsOn: [] + jobs: + - template: /azure-pipelines/templates/test.yml@self + + - stage: LinuxUnitTests + dependsOn: [] + jobs: + - template: /azure-pipelines/templates/test.yml@self + pool: + name: 1es-pool-azfunc + image: 1es-ubuntu-22.04 + os: linux + + - stage: Build + dependsOn: [] + jobs: + - template: /azure-pipelines/templates/build.yml@self + parameters: + IsPrerelease: ${{ parameters.IsPrerelease }} diff --git a/azure-pipelines/public-build.yml b/azure-pipelines/public-build.yml new file mode 100644 index 0000000..4147544 --- /dev/null +++ b/azure-pipelines/public-build.yml @@ -0,0 +1,67 @@ +# This build is used for public PR and CI builds. + +trigger: + batch: true + branches: + include: + - v3.x + +pr: + branches: + include: + - v3.x + +schedules: + - cron: '30 10 * * *' + displayName: Nightly build + always: true + branches: + include: + - v3.x + +resources: + repositories: + - repository: 1es + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + +extends: + template: v1/1ES.Unofficial.PipelineTemplate.yml@1es + parameters: + pool: + name: 1es-pool-azfunc-public + image: 1es-windows-2022 + os: windows + + sdl: + codeql: + compiled: + enabled: true + runSourceLanguagesInSourceAnalysis: true + + settings: + # PR's from forks do not have sufficient permissions to set tags. + skipBuildTagsForGitHubPullRequests: ${{ variables['System.PullRequest.IsFork'] }} + + stages: + - stage: WindowsUnitTests + dependsOn: [] + jobs: + - template: /azure-pipelines/templates/test.yml@self + + - stage: LinuxUnitTests + dependsOn: [] + jobs: + - template: /azure-pipelines/templates/test.yml@self + pool: + name: 1es-pool-azfunc-public + image: 1es-ubuntu-22.04 + os: linux + + - stage: Build + dependsOn: [] + jobs: + - template: /azure-pipelines/templates/build.yml@self + parameters: + IsPrerelease: true diff --git a/azure-pipelines/release.yml b/azure-pipelines/release.yml index 73bcd61..a4a822c 100644 --- a/azure-pipelines/release.yml +++ b/azure-pipelines/release.yml @@ -1,43 +1,65 @@ parameters: -- name: NpmPublishTag - displayName: 'Tag' - type: string - default: 'latest' -- name: NpmPublishDryRun - displayName: 'Dry Run' - type: boolean - default: true + - name: NpmPublishTag + displayName: 'Tag' + type: string + default: 'legacy' + - name: NpmPublishDryRun + displayName: 'Dry Run' + type: boolean + default: true trigger: none pr: none resources: - pipelines: - - pipeline: nodeLibraryCI - project: 'Azure Functions' - source: azure-functions-nodejs-library.build - branch: v3.x + repositories: + - repository: 1es + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + pipelines: + - pipeline: officialBuild + project: internal + source: nodejs-library.official + branch: v3.x -jobs: -- job: ReleaseTypes - pool: - name: '1ES-Hosted-AzFunc' - demands: - - ImageOverride -equals MMSUbuntu20.04TLS - steps: - - task: NodeTool@0 - displayName: 'Install Node.js' - inputs: - versionSpec: 14.x - - download: nodeLibraryCI - - script: mv *.tgz package.tgz - displayName: 'Rename tgz file' # because the publish command below requires an exact path - workingDirectory: '$(Pipeline.Workspace)/nodeLibraryCI/drop' - - task: Npm@1 - displayName: 'npm publish' - inputs: - command: custom - workingDir: '$(Pipeline.Workspace)/nodeLibraryCI/drop' - verbose: true - customCommand: 'publish package.tgz --tag ${{ parameters.NpmPublishTag }} --dry-run ${{ lower(parameters.NpmPublishDryRun) }}' - customEndpoint: 'Functions Node.js Library Publish' \ No newline at end of file +extends: + template: v1/1ES.Official.PipelineTemplate.yml@1es + parameters: + sdl: + sourceAnalysisPool: + name: 1es-pool-azfunc + image: 1es-windows-2022 + os: windows + codeql: + runSourceLanguagesInSourceAnalysis: true + + stages: + - stage: Release + pool: + name: 1es-pool-azfunc + image: 1es-ubuntu-22.04 + os: linux + jobs: + - job: Release + steps: + - download: officialBuild + - task: NodeTool@0 + displayName: 'Install Node.js' + inputs: + versionSpec: 14.x + - script: npm ci + displayName: 'npm ci' + - script: 'npm run validateRelease -- --publishTag ${{ parameters.NpmPublishTag }} --dropPath "$(Pipeline.Workspace)/officialBuild/drop"' + displayName: 'validate release' + - script: mv *.tgz package.tgz + displayName: 'Rename tgz file' # because the publish command below requires an exact path + workingDirectory: '$(Pipeline.Workspace)/officialBuild/drop' + - task: Npm@1 + displayName: 'npm publish' + inputs: + command: custom + workingDir: '$(Pipeline.Workspace)/officialBuild/drop' + verbose: true + customCommand: 'publish package.tgz --tag ${{ parameters.NpmPublishTag }} --dry-run ${{ lower(parameters.NpmPublishDryRun) }}' + customEndpoint: nodejs-library-npm diff --git a/azure-pipelines/templates/build.yml b/azure-pipelines/templates/build.yml new file mode 100644 index 0000000..2b8a464 --- /dev/null +++ b/azure-pipelines/templates/build.yml @@ -0,0 +1,48 @@ +jobs: + - job: + templateContext: + outputs: + - output: pipelineArtifact + path: $(Build.ArtifactStagingDirectory)/dropOutput + artifact: drop + sbomBuildDropPath: '$(Build.ArtifactStagingDirectory)/dropInput' + sbomPackageName: 'Azure Functions Node.js Programming Model' + # The list of components can't be determined from the webpacked file in the staging dir, so reference the original node_modules folder + sbomBuildComponentPath: '$(Build.SourcesDirectory)/node_modules' + steps: + - task: NodeTool@0 + inputs: + versionSpec: 20.x + displayName: 'Install Node.js' + - script: npm ci + displayName: 'npm ci' + - script: npm audit --production + displayName: 'Run vulnerability scan' + - script: npm run updateVersion -- --buildNumber $(Build.BuildNumber) + displayName: 'npm run updateVersion' + condition: and(succeeded(), eq(${{ parameters.IsPrerelease }}, true)) + - script: npm run build + displayName: 'npm run build' + - script: npm run minify + displayName: 'npm run minify' + - task: CopyFiles@2 + displayName: 'Copy files to staging' + inputs: + sourceFolder: '$(Build.SourcesDirectory)' + contents: | + dist/** + src/** + types/** + LICENSE + package.json + README.md + targetFolder: '$(Build.ArtifactStagingDirectory)/dropInput' + cleanTargetFolder: true + - script: npm prune --production + displayName: 'npm prune --production' # so that only production dependencies are included in SBOM + - script: npm pack + displayName: 'npm pack' + workingDirectory: '$(Build.ArtifactStagingDirectory)/dropInput' + - script: mkdir dropOutput && mv dropInput/*.tgz dropOutput + displayName: 'Move package to dropOutput' + workingDirectory: '$(Build.ArtifactStagingDirectory)' diff --git a/azure-pipelines/templates/test.yml b/azure-pipelines/templates/test.yml new file mode 100644 index 0000000..87e4789 --- /dev/null +++ b/azure-pipelines/templates/test.yml @@ -0,0 +1,37 @@ +jobs: + - job: UnitTests + + strategy: + matrix: + Node16: + NODE_VERSION: '16.x' + Node18: + NODE_VERSION: '18.x' + Node20: + NODE_VERSION: '20.x' + Node22: + NODE_VERSION: '22.x' + Node24: + NODE_VERSION: '24.x' + + steps: + - task: NodeTool@0 + inputs: + versionSpec: $(NODE_VERSION) + displayName: 'Install Node.js' + - script: npm ci + displayName: 'npm ci' + - script: npm run build + displayName: 'npm run build' + - script: npm run lint + displayName: 'npm run lint' + - script: npm run updateVersion -- --validate + displayName: 'validate version' + - script: npm test + displayName: 'Run unit tests' + - task: PublishTestResults@2 + displayName: 'Publish Unit Test Results' + inputs: + testResultsFiles: 'test/unit-test-results.xml' + testRunTitle: '$(Agent.JobName)' + condition: succeededOrFailed() diff --git a/azure-pipelines/test.yml b/azure-pipelines/test.yml deleted file mode 100644 index a3a0548..0000000 --- a/azure-pipelines/test.yml +++ /dev/null @@ -1,68 +0,0 @@ -variables: { - NODE_14: '14.x', - NODE_16: '16.x', - NODE_18: '18.x' -} - -pr: - branches: - include: - - v3.x - -trigger: -- v3.x - -jobs: -- job: UnitTests - strategy: - matrix: - UBUNTU_NODE14: - IMAGE_TYPE: 'ubuntu-latest' - NODE_VERSION: $(NODE_14) - UBUNTU_NODE16: - IMAGE_TYPE: 'ubuntu-latest' - NODE_VERSION: $(NODE_16) - UBUNTU_NODE18: - IMAGE_TYPE: 'ubuntu-latest' - NODE_VERSION: $(NODE_18) - WINDOWS_NODE14: - IMAGE_TYPE: 'windows-latest' - NODE_VERSION: $(NODE_14) - WINDOWS_NODE16: - IMAGE_TYPE: 'windows-latest' - NODE_VERSION: $(NODE_16) - WINDOWS_NODE18: - IMAGE_TYPE: 'windows-latest' - NODE_VERSION: $(NODE_18) - MAC_NODE14: - IMAGE_TYPE: 'macOS-latest' - NODE_VERSION: $(NODE_14) - MAC_NODE16: - IMAGE_TYPE: 'macOS-latest' - NODE_VERSION: $(NODE_16) - MAC_NODE18: - IMAGE_TYPE: 'macOS-latest' - NODE_VERSION: $(NODE_18) - pool: - vmImage: $(IMAGE_TYPE) - steps: - - task: NodeTool@0 - inputs: - versionSpec: $(NODE_VERSION) - displayName: 'Install Node.js' - - script: npm ci - displayName: 'npm ci' - - script: npm run build - displayName: 'npm run build' - - script: npm run lint - displayName: 'npm run lint' - - script: npm run updateVersion -- --validate - displayName: 'validate version' - - script: npm test - displayName: 'Run unit tests' - - task: PublishTestResults@2 - displayName: 'Publish Unit Test Results' - inputs: - testResultsFiles: 'test/unit-test-results.xml' - testRunTitle: '$(Agent.JobName)' - condition: succeededOrFailed() diff --git a/package-lock.json b/package-lock.json index faf603c..ccc677d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,17 @@ { "name": "@azure/functions", - "version": "3.5.0-alpha.1", + "version": "3.5.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@azure/functions", - "version": "3.5.0-alpha.1", + "version": "3.5.2", "license": "MIT", "dependencies": { - "fs-extra": "^10.0.1", + "iconv-lite": "^0.6.3", "long": "^4.0.0", - "uuid": "^8.3.0" + "uuid": "8.3.2" }, "devDependencies": { "@types/chai": "^4.2.22", @@ -20,12 +20,9 @@ "@types/long": "^4.0.2", "@types/minimist": "^1.2.2", "@types/mocha": "^9.1.1", - "@types/mock-fs": "^4.13.1", - "@types/mock-require": "^2.0.1", "@types/node": "^16.9.6", "@types/semver": "^7.3.9", "@types/sinon": "^7.0.0", - "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^5.12.1", "@typescript-eslint/parser": "^5.12.1", "chai": "^4.2.0", @@ -35,24 +32,24 @@ "eslint-plugin-deprecation": "^1.3.2", "eslint-plugin-header": "^3.1.1", "eslint-plugin-prettier": "^4.0.0", + "eslint-webpack-plugin": "^3.2.0", + "fork-ts-checker-webpack-plugin": "^7.2.13", + "fs-extra": "^10.0.1", "globby": "^11.0.0", "minimist": "^1.2.6", "mocha": "^9.1.1", "mocha-junit-reporter": "^2.0.2", "mocha-multi-reporters": "^1.5.1", - "mock-fs": "^5.1.2", - "mock-require": "^2.0.2", "prettier": "^2.4.1", - "rimraf": "^2.6.3", "semver": "^7.3.5", - "shx": "^0.3.3", "sinon": "^7.0.0", + "ts-loader": "^9.3.1", "ts-node": "^3.3.0", "typescript": "^4.5.5", "typescript3": "npm:typescript@~3.7.0", "typescript4": "npm:typescript@~4.0.0", - "webpack": "^5.72.1", - "webpack-cli": "^4.8.0" + "webpack": "^5.74.0", + "webpack-cli": "^4.10.0" } }, "node_modules/@babel/code-frame": { @@ -65,21 +62,21 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.14.5", + "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -435,30 +432,18 @@ "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", "dev": true }, - "node_modules/@types/mock-fs": { - "version": "4.13.1", - "resolved": "https://registry.npmjs.org/@types/mock-fs/-/mock-fs-4.13.1.tgz", - "integrity": "sha512-m6nFAJ3lBSnqbvDZioawRvpLXSaPyn52Srf7OfzjubYbYX8MTUdIgDxQl0wEapm4m/pNYSd9TXocpQ0TvZFlYA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/mock-require": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/mock-require/-/mock-require-2.0.1.tgz", - "integrity": "sha512-O7U5DVGboY/Crueb5/huUCIRjKtRVRaLmRDbZJBlDQgJn966z3aiFDN+6AtYviu2ExwMkl34LjT/IiC0OPtKuQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/node": { "version": "16.10.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.3.tgz", "integrity": "sha512-ho3Ruq+fFnBrZhUYI46n/bV2GjwzSkwuT4dTf0GkuNFmnb8nq4ny2z9JEVemFi6bdEJanHLlYfy9c6FN9B9McQ==", "dev": true }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, "node_modules/@types/semver": { "version": "7.3.9", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz", @@ -471,12 +456,6 @@ "integrity": "sha512-T+m89VdXj/eidZyejvmoP9jivXgBDdkOSBVQjU9kF349NEx10QdPNGxHeZUaj1IlJ32/ewdyXJjnJxyxJroYwg==", "dev": true }, - "node_modules/@types/uuid": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", - "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", - "dev": true - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.12.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.12.1.tgz", @@ -841,9 +820,9 @@ } }, "node_modules/@webpack-cli/configtest": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.0.tgz", - "integrity": "sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", "dev": true, "peerDependencies": { "webpack": "4.x.x || 5.x.x", @@ -851,9 +830,9 @@ } }, "node_modules/@webpack-cli/info": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.0.tgz", - "integrity": "sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", "dev": true, "dependencies": { "envinfo": "^7.7.3" @@ -863,9 +842,9 @@ } }, "node_modules/@webpack-cli/serve": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.0.tgz", - "integrity": "sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", "dev": true, "peerDependencies": { "webpack-cli": "4.x.x" @@ -889,9 +868,9 @@ "dev": true }, "node_modules/acorn": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", - "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -934,6 +913,45 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, "node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -1112,18 +1130,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "node_modules/caller-id": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-id/-/caller-id-0.1.0.tgz", - "integrity": "sha1-Wb2sCJPRLDhxQIJ5Ix+XRYNk8Hs=", - "dev": true, - "dependencies": { - "stack-trace": "~0.0.7" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1292,6 +1298,22 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "node_modules/cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -1356,6 +1378,15 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -1402,9 +1433,9 @@ "dev": true }, "node_modules/enhanced-resolve": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", - "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -1438,6 +1469,15 @@ "node": ">=4" } }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/es-module-lexer": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.2.tgz", @@ -1775,6 +1815,121 @@ "node": ">=10" } }, + "node_modules/eslint-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", + "dev": true, + "dependencies": { + "@types/eslint": "^7.29.0 || ^8.4.1", + "jest-worker": "^28.0.2", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/eslint-webpack-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/eslint-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/eslint/node_modules/ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -1926,29 +2081,6 @@ "node": ">=0.8.x" } }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2087,10 +2219,57 @@ "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", "dev": true }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "7.2.13", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-7.2.13.tgz", + "integrity": "sha512-fR3WRkOb4bQdWB/y7ssDUlVdrclvwtyCUIHCfivAoYxq9dF7XfrDKbMdZIfwJ7hxIAqkYSGeU7lLJE6xrxIBdg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cosmiconfig": "^7.0.1", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">=12.13.0", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "typescript": ">3.6.0", + "vue-template-compiler": "*", + "webpack": "^5.11.0" + }, + "peerDependenciesMeta": { + "vue-template-compiler": { + "optional": true + } + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/fs-extra": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", + "dev": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -2100,6 +2279,12 @@ "node": ">=12" } }, + "node_modules/fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", + "dev": true + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2150,18 +2335,6 @@ "node": "*" } }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -2238,7 +2411,8 @@ "node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true }, "node_modules/growl": { "version": "1.10.5", @@ -2291,13 +2465,15 @@ "node": ">=0.10.0" } }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, "engines": { - "node": ">=10.17.0" + "node": ">=0.10.0" } }, "node_modules/ignore": { @@ -2375,14 +2551,11 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true, - "engines": { - "node": ">= 0.10" - } + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true }, "node_modules/is-binary-path": { "version": "2.1.0", @@ -2474,18 +2647,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -2597,6 +2758,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, "dependencies": { "universalify": "^2.0.0" }, @@ -2632,6 +2794,12 @@ "node": ">= 0.8.0" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, "node_modules/loader-runner": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", @@ -2742,6 +2910,18 @@ "is-buffer": "~1.1.6" } }, + "node_modules/memfs": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.7.tgz", + "integrity": "sha512-ygaiUSNalBX85388uskeCyhSAoOSgzBbtVCr9jA2RROssFL9Q19/ZXFqS+2Th2sr1ewNIWgFdLzLC3Yl1Zv+lw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.3" + }, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -2791,19 +2971,10 @@ "node": ">= 0.6" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -2831,9 +3002,9 @@ } }, "node_modules/mocha": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.0.tgz", - "integrity": "sha512-kNn7E8g2SzVcq0a77dkphPsDSN7P+iYkqE0ZsGCYWRsoiKjOt+NvXfaagik8vuDa6W5Zw3qxe8Jfpt5qKf+6/Q==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", "dev": true, "dependencies": { "@ungap/promise-all-settled": "1.1.2", @@ -2849,9 +3020,9 @@ "he": "1.2.0", "js-yaml": "4.1.0", "log-symbols": "4.1.0", - "minimatch": "3.0.4", + "minimatch": "4.2.1", "ms": "2.1.3", - "nanoid": "3.2.0", + "nanoid": "3.3.1", "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", @@ -2949,6 +3120,18 @@ "node": ">=8" } }, + "node_modules/mocha/node_modules/minimatch": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/mocha/node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -3020,27 +3203,6 @@ "node": ">=10" } }, - "node_modules/mock-fs": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-5.1.2.tgz", - "integrity": "sha512-YkjQkdLulFrz0vD4BfNQdQRVmgycXTV7ykuHMlyv+C8WCHazpkiQRDthwa02kSyo8wKnY9wRptHfQLgmf0eR+A==", - "dev": true, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/mock-require": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/mock-require/-/mock-require-2.0.2.tgz", - "integrity": "sha1-HqpxqtIwE3c9En3H6Ro/u0g31g0=", - "dev": true, - "dependencies": { - "caller-id": "^0.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -3048,9 +3210,9 @@ "dev": true }, "node_modules/nanoid": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", "dev": true, "bin": { "nanoid": "bin/nanoid.cjs" @@ -3084,6 +3246,12 @@ "path-to-regexp": "^1.7.0" } }, + "node_modules/node-abort-controller": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.0.1.tgz", + "integrity": "sha512-/ujIVxthRs+7q6hsdjHMaj8hRG9NuWmwrz+JdRwZ14jdFoKSkm+vDsCbF9PLpnSqjaWQJuTmVtcWHNLr+vrOFw==", + "dev": true + }, "node_modules/node-releases": { "version": "1.1.77", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz", @@ -3099,18 +3267,6 @@ "node": ">=0.10.0" } }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3120,21 +3276,6 @@ "wrappy": "1" } }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -3203,6 +3344,24 @@ "node": ">=6" } }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", @@ -3452,18 +3611,6 @@ "node": ">=8.10.0" } }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -3538,18 +3685,6 @@ "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -3579,6 +3714,11 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "node_modules/schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -3654,45 +3794,6 @@ "node": ">=8" } }, - "node_modules/shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "dev": true, - "dependencies": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "bin": { - "shjs": "bin/shjs" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/shx": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.3.tgz", - "integrity": "sha512-nZJ3HFWVoTSyyB+evEKjJ1STiixGztlqwKLTUNV5KqMWtGey9fTd4KU1gdZ1X9BV6215pswQ/Jew9NsuS/fNDA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.3", - "shelljs": "^0.8.4" - }, - "bin": { - "shx": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/signal-exit": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", - "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", - "dev": true - }, "node_modules/sinon": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz", @@ -3770,15 +3871,6 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -3814,15 +3906,6 @@ "node": ">=4" } }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -3994,10 +4077,29 @@ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "dependencies": { - "is-number": "^7.0.0" + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-loader": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.1.tgz", + "integrity": "sha512-384TYAqGs70rn9F0VBnh6BPTfhga7yFNdC5gXbQpDrBj9/KsT4iRkGqKXhziofHOlE2j6YEaiTYVGKKvPhGWvw==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" }, "engines": { - "node": ">=8.0" + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" } }, "node_modules/ts-node": { @@ -4182,6 +4284,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, "engines": { "node": ">= 10.0.0" } @@ -4196,9 +4299,11 @@ } }, "node_modules/uuid": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.0.tgz", - "integrity": "sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -4222,9 +4327,9 @@ } }, "node_modules/watchpack": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", - "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", "dev": true, "dependencies": { "glob-to-regexp": "^0.4.1", @@ -4235,9 +4340,9 @@ } }, "node_modules/webpack": { - "version": "5.72.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.1.tgz", - "integrity": "sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung==", + "version": "5.76.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.0.tgz", + "integrity": "sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -4245,11 +4350,11 @@ "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", + "acorn": "^8.7.1", "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.3", + "enhanced-resolve": "^5.10.0", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -4262,7 +4367,7 @@ "schema-utils": "^3.1.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", + "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, "bin": { @@ -4282,23 +4387,22 @@ } }, "node_modules/webpack-cli": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.0.tgz", - "integrity": "sha512-n/jZZBMzVEl4PYIBs+auy2WI0WTQ74EnJDiyD98O2JZY6IVIHJNitkYp/uTXOviIOMfgzrNvC9foKv/8o8KSZw==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", + "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", "dev": true, "dependencies": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.1.0", - "@webpack-cli/info": "^1.4.0", - "@webpack-cli/serve": "^1.6.0", + "@webpack-cli/configtest": "^1.2.0", + "@webpack-cli/info": "^1.5.0", + "@webpack-cli/serve": "^1.7.0", "colorette": "^2.0.14", "commander": "^7.0.0", - "execa": "^5.0.0", + "cross-spawn": "^7.0.3", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", "interpret": "^2.2.0", "rechoir": "^0.7.0", - "v8-compile-cache": "^2.2.0", "webpack-merge": "^5.7.3" }, "bin": { @@ -4307,6 +4411,10 @@ "engines": { "node": ">=10.13.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, "peerDependencies": { "webpack": "4.x.x || 5.x.x" }, @@ -4399,9 +4507,9 @@ "dev": true }, "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "dev": true, "engines": { "node": ">=0.10.0" @@ -4425,6 +4533,15 @@ "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=", "dev": true }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/yargs-parser": { "version": "20.2.4", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", @@ -4506,18 +4623,18 @@ } }, "@babel/helper-validator-identifier": { - "version": "7.15.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", - "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "dev": true }, "@babel/highlight": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", - "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.14.5", + "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -4823,30 +4940,18 @@ "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", "dev": true }, - "@types/mock-fs": { - "version": "4.13.1", - "resolved": "https://registry.npmjs.org/@types/mock-fs/-/mock-fs-4.13.1.tgz", - "integrity": "sha512-m6nFAJ3lBSnqbvDZioawRvpLXSaPyn52Srf7OfzjubYbYX8MTUdIgDxQl0wEapm4m/pNYSd9TXocpQ0TvZFlYA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/mock-require": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/mock-require/-/mock-require-2.0.1.tgz", - "integrity": "sha512-O7U5DVGboY/Crueb5/huUCIRjKtRVRaLmRDbZJBlDQgJn966z3aiFDN+6AtYviu2ExwMkl34LjT/IiC0OPtKuQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/node": { "version": "16.10.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-16.10.3.tgz", "integrity": "sha512-ho3Ruq+fFnBrZhUYI46n/bV2GjwzSkwuT4dTf0GkuNFmnb8nq4ny2z9JEVemFi6bdEJanHLlYfy9c6FN9B9McQ==", "dev": true }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, "@types/semver": { "version": "7.3.9", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz", @@ -4859,12 +4964,6 @@ "integrity": "sha512-T+m89VdXj/eidZyejvmoP9jivXgBDdkOSBVQjU9kF349NEx10QdPNGxHeZUaj1IlJ32/ewdyXJjnJxyxJroYwg==", "dev": true }, - "@types/uuid": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", - "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", - "dev": true - }, "@typescript-eslint/eslint-plugin": { "version": "5.12.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.12.1.tgz", @@ -5134,25 +5233,25 @@ } }, "@webpack-cli/configtest": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.0.tgz", - "integrity": "sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", "dev": true, "requires": {} }, "@webpack-cli/info": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.0.tgz", - "integrity": "sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", "dev": true, "requires": { "envinfo": "^7.7.3" } }, "@webpack-cli/serve": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.0.tgz", - "integrity": "sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", "dev": true, "requires": {} }, @@ -5169,9 +5268,9 @@ "dev": true }, "acorn": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", - "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", "dev": true }, "acorn-import-assertions": { @@ -5200,6 +5299,35 @@ "uri-js": "^4.2.2" } }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "requires": { + "ajv": "^8.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, "ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -5333,15 +5461,6 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "caller-id": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-id/-/caller-id-0.1.0.tgz", - "integrity": "sha1-Wb2sCJPRLDhxQIJ5Ix+XRYNk8Hs=", - "dev": true, - "requires": { - "stack-trace": "~0.0.7" - } - }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -5465,6 +5584,19 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "dev": true, + "requires": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -5514,6 +5646,12 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "dev": true + }, "diff": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", @@ -5551,9 +5689,9 @@ "dev": true }, "enhanced-resolve": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", - "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", "dev": true, "requires": { "graceful-fs": "^4.2.4", @@ -5575,6 +5713,15 @@ "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", "dev": true }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, "es-module-lexer": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.2.tgz", @@ -5825,6 +5972,86 @@ "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true }, + "eslint-webpack-plugin": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz", + "integrity": "sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==", + "dev": true, + "requires": { + "@types/eslint": "^7.29.0 || ^8.4.1", + "jest-worker": "^28.0.2", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "espree": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", @@ -5908,23 +6135,6 @@ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -6038,16 +6248,54 @@ "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", "dev": true }, + "fork-ts-checker-webpack-plugin": { + "version": "7.2.13", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-7.2.13.tgz", + "integrity": "sha512-fR3WRkOb4bQdWB/y7ssDUlVdrclvwtyCUIHCfivAoYxq9dF7XfrDKbMdZIfwJ7hxIAqkYSGeU7lLJE6xrxIBdg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cosmiconfig": "^7.0.1", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + } + } + }, "fs-extra": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", + "dev": true, "requires": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, + "fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", + "dev": true + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -6085,12 +6333,6 @@ "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", "dev": true }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, "glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -6146,7 +6388,8 @@ "graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true }, "growl": { "version": "1.10.5", @@ -6184,11 +6427,13 @@ "parse-passwd": "^1.0.0" } }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } }, "ignore": { "version": "5.2.0", @@ -6246,10 +6491,10 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, "is-binary-path": { @@ -6318,12 +6563,6 @@ "isobject": "^3.0.1" } }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, "is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -6415,6 +6654,7 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, "requires": { "graceful-fs": "^4.1.6", "universalify": "^2.0.0" @@ -6442,6 +6682,12 @@ "type-check": "~0.4.0" } }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, "loader-runner": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", @@ -6536,6 +6782,15 @@ "is-buffer": "~1.1.6" } }, + "memfs": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.7.tgz", + "integrity": "sha512-ygaiUSNalBX85388uskeCyhSAoOSgzBbtVCr9jA2RROssFL9Q19/ZXFqS+2Th2sr1ewNIWgFdLzLC3Yl1Zv+lw==", + "dev": true, + "requires": { + "fs-monkey": "^1.0.3" + } + }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -6573,16 +6828,10 @@ "mime-db": "1.50.0" } }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -6604,9 +6853,9 @@ } }, "mocha": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.0.tgz", - "integrity": "sha512-kNn7E8g2SzVcq0a77dkphPsDSN7P+iYkqE0ZsGCYWRsoiKjOt+NvXfaagik8vuDa6W5Zw3qxe8Jfpt5qKf+6/Q==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", "dev": true, "requires": { "@ungap/promise-all-settled": "1.1.2", @@ -6622,9 +6871,9 @@ "he": "1.2.0", "js-yaml": "4.1.0", "log-symbols": "4.1.0", - "minimatch": "3.0.4", + "minimatch": "4.2.1", "ms": "2.1.3", - "nanoid": "3.2.0", + "nanoid": "3.3.1", "serialize-javascript": "6.0.0", "strip-json-comments": "3.1.1", "supports-color": "8.1.1", @@ -6658,6 +6907,15 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "minimatch": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -6747,21 +7005,6 @@ "lodash": "^4.17.15" } }, - "mock-fs": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-5.1.2.tgz", - "integrity": "sha512-YkjQkdLulFrz0vD4BfNQdQRVmgycXTV7ykuHMlyv+C8WCHazpkiQRDthwa02kSyo8wKnY9wRptHfQLgmf0eR+A==", - "dev": true - }, - "mock-require": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/mock-require/-/mock-require-2.0.2.tgz", - "integrity": "sha1-HqpxqtIwE3c9En3H6Ro/u0g31g0=", - "dev": true, - "requires": { - "caller-id": "^0.1.0" - } - }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -6769,9 +7012,9 @@ "dev": true }, "nanoid": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", "dev": true }, "natural-compare": { @@ -6799,6 +7042,12 @@ "path-to-regexp": "^1.7.0" } }, + "node-abort-controller": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.0.1.tgz", + "integrity": "sha512-/ujIVxthRs+7q6hsdjHMaj8hRG9NuWmwrz+JdRwZ14jdFoKSkm+vDsCbF9PLpnSqjaWQJuTmVtcWHNLr+vrOFw==", + "dev": true + }, "node-releases": { "version": "1.1.77", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz", @@ -6811,15 +7060,6 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -6829,15 +7069,6 @@ "wrappy": "1" } }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -6885,6 +7116,18 @@ "callsites": "^3.0.0" } }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, "parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", @@ -7061,15 +7304,6 @@ "picomatch": "^2.2.1" } }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "requires": { - "resolve": "^1.1.6" - } - }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -7119,15 +7353,6 @@ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -7143,6 +7368,11 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -7196,33 +7426,6 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, - "shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "dev": true, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - } - }, - "shx": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.3.tgz", - "integrity": "sha512-nZJ3HFWVoTSyyB+evEKjJ1STiixGztlqwKLTUNV5KqMWtGey9fTd4KU1gdZ1X9BV6215pswQ/Jew9NsuS/fNDA==", - "dev": true, - "requires": { - "minimist": "^1.2.3", - "shelljs": "^0.8.4" - } - }, - "signal-exit": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", - "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", - "dev": true - }, "sinon": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/sinon/-/sinon-7.5.0.tgz", @@ -7289,12 +7492,6 @@ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", - "dev": true - }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -7321,12 +7518,6 @@ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, "strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -7459,6 +7650,18 @@ "is-number": "^7.0.0" } }, + "ts-loader": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.1.tgz", + "integrity": "sha512-384TYAqGs70rn9F0VBnh6BPTfhga7yFNdC5gXbQpDrBj9/KsT4iRkGqKXhziofHOlE2j6YEaiTYVGKKvPhGWvw==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" + } + }, "ts-node": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-3.3.0.tgz", @@ -7596,7 +7799,8 @@ "universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true }, "uri-js": { "version": "4.4.1", @@ -7608,9 +7812,9 @@ } }, "uuid": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.0.tgz", - "integrity": "sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==" + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, "v8-compile-cache": { "version": "2.3.0", @@ -7628,9 +7832,9 @@ } }, "watchpack": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", - "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", "dev": true, "requires": { "glob-to-regexp": "^0.4.1", @@ -7638,9 +7842,9 @@ } }, "webpack": { - "version": "5.72.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.1.tgz", - "integrity": "sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung==", + "version": "5.76.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.0.tgz", + "integrity": "sha512-l5sOdYBDunyf72HW8dF23rFtWq/7Zgvt/9ftMof71E/yUb1YLOBmTgA2K4vQthB3kotMrSj609txVE0dnr2fjA==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.3", @@ -7648,11 +7852,11 @@ "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", + "acorn": "^8.7.1", "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.3", + "enhanced-resolve": "^5.10.0", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -7665,28 +7869,27 @@ "schema-utils": "^3.1.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", + "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" } }, "webpack-cli": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.0.tgz", - "integrity": "sha512-n/jZZBMzVEl4PYIBs+auy2WI0WTQ74EnJDiyD98O2JZY6IVIHJNitkYp/uTXOviIOMfgzrNvC9foKv/8o8KSZw==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", + "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", "dev": true, "requires": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.1.0", - "@webpack-cli/info": "^1.4.0", - "@webpack-cli/serve": "^1.6.0", + "@webpack-cli/configtest": "^1.2.0", + "@webpack-cli/info": "^1.5.0", + "@webpack-cli/serve": "^1.7.0", "colorette": "^2.0.14", "commander": "^7.0.0", - "execa": "^5.0.0", + "cross-spawn": "^7.0.3", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", "interpret": "^2.2.0", "rechoir": "^0.7.0", - "v8-compile-cache": "^2.2.0", "webpack-merge": "^5.7.3" }, "dependencies": { @@ -7745,9 +7948,9 @@ "dev": true }, "word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", + "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", "dev": true }, "workerpool": { @@ -7768,6 +7971,12 @@ "integrity": "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU=", "dev": true }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + }, "yargs-parser": { "version": "20.2.4", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", diff --git a/package.json b/package.json index 8b797ca..0f33475 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@azure/functions", - "version": "3.5.0-alpha.1", + "version": "3.5.2", "description": "Microsoft Azure Functions NodeJS Framework", "keywords": [ "azure", @@ -18,29 +18,28 @@ "bugs": { "url": "https://github.com/Azure/azure-functions-nodejs-library/issues" }, - "main": "dist/src/index-bundle.js", + "main": "./dist/azure-functions.js", "types": "types/index.d.ts", "files": [ - "dist/src/index-bundle.js", - "types/index.d.ts", + "dist/", + "src/", + "types/", "LICENSE", - "README.md", - "NOTICE.html", - "_manifest" + "README.md" ], "scripts": { - "build": "node ./node_modules/typescript/bin/tsc", - "test": "node ./dist/test/index.js", - "lint": "eslint .", - "lint-fix": "eslint . --fix", + "build": "webpack --mode development", + "minify": "webpack --mode production", + "test": "ts-node ./test/index.ts", + "lint": "eslint . --fix", "updateVersion": "ts-node ./scripts/updateVersion.ts", - "watch": "node ./node_modules/typescript/bin/tsc --watch", - "webpack": "webpack --mode production" + "validateRelease": "ts-node ./scripts/validateRelease.ts", + "watch": "webpack --watch --mode development" }, "dependencies": { - "fs-extra": "^10.0.1", + "iconv-lite": "^0.6.3", "long": "^4.0.0", - "uuid": "^8.3.0" + "uuid": "8.3.2" }, "devDependencies": { "@types/chai": "^4.2.22", @@ -49,12 +48,9 @@ "@types/long": "^4.0.2", "@types/minimist": "^1.2.2", "@types/mocha": "^9.1.1", - "@types/mock-fs": "^4.13.1", - "@types/mock-require": "^2.0.1", "@types/node": "^16.9.6", "@types/semver": "^7.3.9", "@types/sinon": "^7.0.0", - "@types/uuid": "^8.3.4", "@typescript-eslint/eslint-plugin": "^5.12.1", "@typescript-eslint/parser": "^5.12.1", "chai": "^4.2.0", @@ -64,23 +60,23 @@ "eslint-plugin-deprecation": "^1.3.2", "eslint-plugin-header": "^3.1.1", "eslint-plugin-prettier": "^4.0.0", + "eslint-webpack-plugin": "^3.2.0", + "fork-ts-checker-webpack-plugin": "^7.2.13", + "fs-extra": "^10.0.1", "globby": "^11.0.0", "minimist": "^1.2.6", "mocha": "^9.1.1", "mocha-junit-reporter": "^2.0.2", "mocha-multi-reporters": "^1.5.1", - "mock-fs": "^5.1.2", - "mock-require": "^2.0.2", "prettier": "^2.4.1", - "rimraf": "^2.6.3", "semver": "^7.3.5", - "shx": "^0.3.3", "sinon": "^7.0.0", + "ts-loader": "^9.3.1", "ts-node": "^3.3.0", "typescript": "^4.5.5", "typescript3": "npm:typescript@~3.7.0", "typescript4": "npm:typescript@~4.0.0", - "webpack": "^5.72.1", - "webpack-cli": "^4.8.0" + "webpack": "^5.74.0", + "webpack-cli": "^4.10.0" } } diff --git a/scripts/updateVersion.ts b/scripts/updateVersion.ts index f7736db..0f17d9a 100644 --- a/scripts/updateVersion.ts +++ b/scripts/updateVersion.ts @@ -17,18 +17,24 @@ if (args.validate) { validateVersion(); } else if (args.version) { updateVersion(args.version); +} else if (args.buildNumber) { + const currentVersion = validateVersion(); + const newVersion = currentVersion.includes('alpha') + ? `${currentVersion}.${args.buildNumber}` + : `${currentVersion}-alpha.${args.buildNumber}`; + updateVersion(newVersion); } else { console.log(`This script can be used to either update the version of the library or validate that the repo is in a valid state with regards to versioning. Example usage: npm run updateVersion -- --version 3.3.0 - +npm run updateVersion -- --buildNumber 20230517.1 npm run updateVersion -- --validate`); throw new Error('Invalid arguments'); } -function validateVersion() { +function validateVersion(): string { const packageJson = readJSONSync(packageJsonPath); const packageJsonVersion = packageJson.version; @@ -46,6 +52,7 @@ function validateVersion() { throw new Error(`Versions do not match.`); } else { console.log('Versions match! 🎉'); + return packageJsonVersion; } } diff --git a/scripts/validateRelease.ts b/scripts/validateRelease.ts new file mode 100644 index 0000000..670730f --- /dev/null +++ b/scripts/validateRelease.ts @@ -0,0 +1,51 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +import { readdirSync } from 'fs-extra'; +import * as parseArgs from 'minimist'; + +const args = parseArgs(process.argv.slice(2)); +if (args.publishTag && args.dropPath) { + validateRelease(args.publishTag, args.dropPath); +} else { + console.log(`This script can be used to validate that a release tag and version are in an expected format + +Example usage: + +npm run validateRelease -- --publishTag preview --dropPath /example/path/`); + throw new Error('Invalid arguments'); +} + +function validateRelease(publishTag: string, dropPath: string): void { + const files = readdirSync(dropPath).filter((f) => f.endsWith('.tgz')); + if (files.length !== 1) { + throw new Error('Drop path should have one tgz file'); + } + + const match = files[0].match(/^azure-functions-(.*)\.tgz$/); + if (!match) { + throw new Error(`Unrecognized tgz file name "${files[0]}"`); + } + + const versionNumber = match[1]; + let regex: RegExp; + let expectedFormat: string; + switch (publishTag) { + case 'preview': + regex = /^[0-9]+\.[0-9]+\.[0-9]+-alpha\.[0-9]+$/; + expectedFormat = 'x.x.x-alpha.x'; + break; + case 'latest': + case 'legacy': + regex = /^[0-9]+\.[0-9]+\.[0-9]+$/; + expectedFormat = 'x.x.x'; + break; + default: + throw new Error(`Unrecognized publish tag "${publishTag}"`); + } + if (!regex.test(versionNumber)) { + throw new Error( + `Version number for tag "${publishTag}" should be in format "${expectedFormat}". Instead got "${versionNumber}"` + ); + } +} diff --git a/src/Context.ts b/src/Context.ts index a45e11d..457b0e4 100644 --- a/src/Context.ts +++ b/src/Context.ts @@ -10,7 +10,7 @@ import { Logger, TraceContext, } from '@azure/functions'; -import { RpcInvocationRequest, RpcLog, RpcParameterBinding } from '@azure/functions-core'; +import { RpcInvocationRequest, RpcLogLevel, RpcParameterBinding } from '@azure/functions-core'; import { v4 as uuid } from 'uuid'; import { convertKeysToCamelCase, @@ -107,11 +107,11 @@ class InvocationContext implements Context { this.bindings = {}; // Log message that is tied to function invocation - this.log = Object.assign((...args: any[]) => userLogCallback(RpcLog.Level.Information, ...args), { - error: (...args: any[]) => userLogCallback(RpcLog.Level.Error, ...args), - warn: (...args: any[]) => userLogCallback(RpcLog.Level.Warning, ...args), - info: (...args: any[]) => userLogCallback(RpcLog.Level.Information, ...args), - verbose: (...args: any[]) => userLogCallback(RpcLog.Level.Trace, ...args), + this.log = Object.assign((...args: any[]) => userLogCallback('information', ...args), { + error: (...args: any[]) => userLogCallback('error', ...args), + warn: (...args: any[]) => userLogCallback('warning', ...args), + info: (...args: any[]) => userLogCallback('information', ...args), + verbose: (...args: any[]) => userLogCallback('trace', ...args), }); this.bindingData = getNormalizedBindingData(request); @@ -130,7 +130,7 @@ export interface InvocationResult { export type DoneCallback = (err?: unknown, result?: any) => void; -export type UserLogCallback = (level: RpcLog.Level, ...args: any[]) => void; +export type UserLogCallback = (level: RpcLogLevel, ...args: any[]) => void; export interface Dict { [key: string]: T; diff --git a/src/FunctionInfo.ts b/src/FunctionInfo.ts index 6643f1a..6ddfd94 100644 --- a/src/FunctionInfo.ts +++ b/src/FunctionInfo.ts @@ -32,7 +32,7 @@ export class FunctionInfo { // determine output bindings & assign rpc converter (http has quirks) Object.keys(bindings) - .filter((name) => bindings[name].direction !== RpcBindingInfo.Direction.in) + .filter((name) => bindings[name].direction !== 'in') .forEach((name) => { const type = bindings[name].type; if (type && type.toLowerCase() === 'http') { diff --git a/src/InvocationModel.ts b/src/InvocationModel.ts index 4c8fbb0..03c269c 100644 --- a/src/InvocationModel.ts +++ b/src/InvocationModel.ts @@ -7,14 +7,15 @@ import { CoreInvocationContext, InvocationArguments, RpcInvocationResponse, - RpcLog, + RpcLogCategory, + RpcLogLevel, RpcParameterBinding, } from '@azure/functions-core'; import { format } from 'util'; import { CreateContextAndInputs } from './Context'; import { toTypedData } from './converters/RpcConverters'; +import { isError } from './errors'; import { FunctionInfo } from './FunctionInfo'; -import { isError } from './utils/ensureErrorType'; import EventEmitter = require('events'); const asyncDoneLearnMoreLink = 'https://go.microsoft.com/fwlink/?linkid=2097909'; @@ -35,7 +36,7 @@ export class InvocationModel implements coreTypes.InvocationModel { const { context, inputs } = CreateContextAndInputs( this.#funcInfo, this.#coreCtx.request, - (level: RpcLog.Level, ...args: any[]) => this.#userLog(level, ...args), + (level: RpcLogLevel, ...args: any[]) => this.#userLog(level, ...args), this.#doneEmitter ); return { context, inputs }; @@ -44,7 +45,7 @@ export class InvocationModel implements coreTypes.InvocationModel { async invokeFunction(context: Context, inputs: unknown[], functionCallback: AzureFunction): Promise { const legacyDoneTask = new Promise((resolve, reject) => { this.#doneEmitter.on('done', (err?: unknown, result?: unknown) => { - this.#onDone(); + this.#onDone(context.suppressAsyncDoneError); if (isError(err)) { reject(err); } else { @@ -59,7 +60,7 @@ export class InvocationModel implements coreTypes.InvocationModel { let resultTask: Promise; if (this.#resultIsPromise) { rawResult = Promise.resolve(rawResult).then((r) => { - this.#onDone(); + this.#onDone(context.suppressAsyncDoneError); return r; }); resultTask = Promise.race([rawResult, legacyDoneTask]); @@ -142,31 +143,35 @@ export class InvocationModel implements coreTypes.InvocationModel { return response; } - #log(level: RpcLog.Level, logCategory: RpcLog.RpcLogCategory, ...args: any[]): void { + #log(level: RpcLogLevel, logCategory: RpcLogCategory, ...args: any[]): void { this.#coreCtx.log(level, logCategory, format.apply(null, <[any, any[]]>args)); } - #systemLog(level: RpcLog.Level, ...args: any[]) { - this.#log(level, RpcLog.RpcLogCategory.System, ...args); + #systemLog(level: RpcLogLevel, ...args: any[]) { + this.#log(level, 'system', ...args); } - #userLog(level: RpcLog.Level, ...args: any[]): void { + #userLog(level: RpcLogLevel, ...args: any[]): void { if (this.#isDone && this.#coreCtx.state !== 'postInvocationHooks') { let badAsyncMsg = "Warning: Unexpected call to 'log' on the context object after function execution has completed. Please check for asynchronous calls that are not awaited or calls to 'done' made before function execution completes. "; badAsyncMsg += `Function name: ${this.#funcInfo.name}. Invocation Id: ${this.#coreCtx.invocationId}. `; badAsyncMsg += `Learn more: ${asyncDoneLearnMoreLink}`; - this.#systemLog(RpcLog.Level.Warning, badAsyncMsg); + this.#systemLog('warning', badAsyncMsg); } - this.#log(level, RpcLog.RpcLogCategory.User, ...args); + this.#log(level, 'user', ...args); } - #onDone(): void { + #onDone(suppressAsyncDoneError = false): void { if (this.#isDone) { + if (this.#resultIsPromise && suppressAsyncDoneError) { + return; + } + const message = this.#resultIsPromise ? `Error: Choose either to return a promise or call 'done'. Do not use both in your script. Learn more: ${asyncDoneLearnMoreLink}` : "Error: 'done' has already been called. Please check your script for extraneous calls to 'done'."; - this.#systemLog(RpcLog.Level.Error, message); + this.#systemLog('error', message); } this.#isDone = true; } diff --git a/src/constants.ts b/src/constants.ts index b6fc04a..189d6b1 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. -export const version = '3.5.0-alpha.1'; +export const version = '3.5.2'; export enum HeaderName { contentType = 'content-type', @@ -10,6 +10,7 @@ export enum HeaderName { export enum MediaType { multipartForm = 'multipart/form-data', + multipartPrefix = 'multipart/', urlEncodedForm = 'application/x-www-form-urlencoded', octetStream = 'application/octet-stream', json = 'application/json', diff --git a/src/converters/BindingConverters.ts b/src/converters/BindingConverters.ts index 84da110..7907ee0 100644 --- a/src/converters/BindingConverters.ts +++ b/src/converters/BindingConverters.ts @@ -2,12 +2,10 @@ // Licensed under the MIT License. import { BindingDefinition, ContextBindingData } from '@azure/functions'; -import { RpcBindingInfo, RpcInvocationRequest } from '@azure/functions-core'; +import { RpcInvocationRequest } from '@azure/functions-core'; import { FunctionInfo } from '../FunctionInfo'; import { fromTypedData } from './RpcConverters'; -type BindingDirection = 'in' | 'out' | 'inout' | undefined; - export function getBindingDefinitions(info: FunctionInfo): BindingDefinition[] { const bindings = info.bindings; if (!bindings) { @@ -18,7 +16,7 @@ export function getBindingDefinitions(info: FunctionInfo): BindingDefinition[] { return { name: name, type: bindings[name].type || '', - direction: getDirectionName(bindings[name].direction), + direction: bindings[name].direction || undefined, }; }); } @@ -35,31 +33,27 @@ export function getNormalizedBindingData(request: RpcInvocationRequest): Context return bindingData; } -function getDirectionName(direction: RpcBindingInfo.Direction | null | undefined): BindingDirection { - const directionName = Object.keys(RpcBindingInfo.Direction).find((k) => RpcBindingInfo.Direction[k] === direction); - return isBindingDirection(directionName) ? (directionName as BindingDirection) : undefined; -} - -function isBindingDirection(input: string | undefined): boolean { - return input == 'in' || input == 'out' || input == 'inout'; -} - // Recursively convert keys of objects to camel case export function convertKeysToCamelCase(obj: any) { const output = {}; for (const key in obj) { - // Only "undefined" will be replaced with original object property. For example: - //{ string : "0" } -> 0 - //{ string : "false" } -> false - //"test" -> "test" (undefined returned from fromTypedData) - const valueFromDataType = fromTypedData(obj[key]); - const value = valueFromDataType === undefined ? obj[key] : valueFromDataType; const camelCasedKey = key.charAt(0).toLocaleLowerCase() + key.slice(1); - // If the value is a JSON object (and not array and not http, which is already cased), convert keys to camel case - if (!Array.isArray(value) && typeof value === 'object' && value && value.http == undefined) { - output[camelCasedKey] = convertKeysToCamelCase(value); - } else { - output[camelCasedKey] = value; + try { + // Only "undefined" will be replaced with original object property. For example: + //{ string : "0" } -> 0 + //{ string : "false" } -> false + //"test" -> "test" (undefined returned from fromTypedData) + const valueFromDataType = fromTypedData(obj[key]); + const value = valueFromDataType === undefined ? obj[key] : valueFromDataType; + // If the value is a JSON object (and not array and not http, which is already cased), convert keys to camel case + if (!Array.isArray(value) && typeof value === 'object' && value && value.http == undefined) { + output[camelCasedKey] = convertKeysToCamelCase(value); + } else { + output[camelCasedKey] = value; + } + } catch { + // Just use the original value if we failed to recursively convert for any reason + output[camelCasedKey] = obj[key]; } } return output; diff --git a/src/converters/RpcConverters.ts b/src/converters/RpcConverters.ts index 80b7ff7..274b254 100644 --- a/src/converters/RpcConverters.ts +++ b/src/converters/RpcConverters.ts @@ -11,7 +11,7 @@ import { RpcTypedData, } from '@azure/functions-core'; import { isLong } from 'long'; -import { InternalException } from '../utils/InternalException'; +import { AzFuncSystemError } from '../errors'; /** * Converts 'ITypedData' input from the RPC layer to JavaScript types. @@ -19,7 +19,7 @@ import { InternalException } from '../utils/InternalException'; * @param typedData ITypedData object containing one of a string, json, or bytes property * @param convertStringToJson Optionally parse the string input type as JSON */ -export function fromTypedData(typedData?: RpcTypedData, convertStringToJson = true) { +export function fromTypedData(typedData?: RpcTypedData | null, convertStringToJson = true) { typedData = typedData || {}; let str = typedData.string || typedData.json; if (str !== undefined) { @@ -100,7 +100,7 @@ export function toNullableBool(nullable: boolean | undefined, propertyName: stri } if (nullable != null) { - throw new InternalException( + throw new AzFuncSystemError( `A 'boolean' type was expected instead of a '${typeof nullable}' type. Cannot parse value of '${propertyName}'.` ); } @@ -132,7 +132,7 @@ export function toNullableDouble( } if (nullable != null) { - throw new InternalException( + throw new AzFuncSystemError( `A 'number' type was expected instead of a '${typeof nullable}' type. Cannot parse value of '${propertyName}'.` ); } @@ -152,7 +152,7 @@ export function toRpcString(nullable: string | undefined, propertyName: string): } if (nullable != null) { - throw new InternalException( + throw new AzFuncSystemError( `A 'string' type was expected instead of a '${typeof nullable}' type. Cannot parse value of '${propertyName}'.` ); } @@ -174,7 +174,7 @@ export function toNullableString(nullable: string | undefined, propertyName: str } if (nullable != null) { - throw new InternalException( + throw new AzFuncSystemError( `A 'string' type was expected instead of a '${typeof nullable}' type. Cannot parse value of '${propertyName}'.` ); } @@ -204,7 +204,7 @@ export function toNullableTimestamp( }; } } catch { - throw new InternalException( + throw new AzFuncSystemError( `A 'number' or 'Date' input was expected instead of a '${typeof dateTime}'. Cannot parse value of '${propertyName}'.` ); } diff --git a/src/converters/RpcHttpConverters.ts b/src/converters/RpcHttpConverters.ts index 8c0ea8c..be28878 100644 --- a/src/converters/RpcHttpConverters.ts +++ b/src/converters/RpcHttpConverters.ts @@ -1,9 +1,16 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. -import { Cookie } from '@azure/functions'; -import { RpcHttpCookie, RpcHttpData, RpcNullableString, RpcTypedData } from '@azure/functions-core'; +import { Cookie, HttpResponse } from '@azure/functions'; +import { + RpcHttpCookie, + RpcHttpCookieSameSite, + RpcHttpData, + RpcNullableString, + RpcTypedData, +} from '@azure/functions-core'; import { Dict } from '../Context'; +import { AzFuncSystemError } from '../errors'; import { fromTypedData, toNullableBool, @@ -20,7 +27,7 @@ import { * This is to avoid breaking changes in v2. * @param body The body from the RPC layer. */ -export function fromRpcHttpBody(body: RpcTypedData) { +export function fromRpcHttpBody(body: RpcTypedData | null | undefined) { if (body && body.bytes) { return (body.bytes).toString(); } else { @@ -48,23 +55,27 @@ export function fromNullableMapping( * 'http' types are a special case from other 'ITypedData' types, which come from primitive types. * @param inputMessage An HTTP response object */ -export function toRpcHttp(inputMessage): RpcTypedData { +export function toRpcHttp(data: unknown): RpcTypedData { // Check if we will fail to find any of these - if (typeof inputMessage !== 'object' || Array.isArray(inputMessage)) { - throw new Error( + if (typeof data !== 'object' || Array.isArray(data)) { + throw new AzFuncSystemError( "The HTTP response must be an 'object' type that can include properties such as 'body', 'status', and 'headers'. Learn more: https://go.microsoft.com/fwlink/?linkid=2112563" ); } - const httpMessage: RpcHttpData = inputMessage; - httpMessage.headers = toRpcHttpHeaders(inputMessage.headers); - httpMessage.cookies = toRpcHttpCookieList(inputMessage.cookies || []); + const inputMessage: HttpResponse = data || {}; let status = inputMessage.statusCode; if (typeof inputMessage.status !== 'function') { status ||= inputMessage.status; } - httpMessage.statusCode = status && status.toString(); - httpMessage.body = toTypedData(inputMessage.body); + const httpMessage: RpcHttpData = { + ...inputMessage, + statusCode: status?.toString() || null, + headers: toRpcHttpHeaders(inputMessage.headers), + cookies: toRpcHttpCookieList(inputMessage.cookies || []), + body: toTypedData(inputMessage.body), + }; + return { http: httpMessage }; } @@ -72,11 +83,13 @@ export function toRpcHttp(inputMessage): RpcTypedData { * Convert HTTP headers to a string/string mapping. * @param inputHeaders */ -function toRpcHttpHeaders(inputHeaders: RpcTypedData) { +function toRpcHttpHeaders(inputHeaders: RpcTypedData | undefined) { const rpcHttpHeaders: { [key: string]: string } = {}; - for (const key in inputHeaders) { - if (inputHeaders[key] != null) { - rpcHttpHeaders[key] = inputHeaders[key].toString(); + if (inputHeaders) { + for (const key in inputHeaders) { + if (inputHeaders[key] != null) { + rpcHttpHeaders[key] = inputHeaders[key].toString(); + } } } return rpcHttpHeaders; @@ -101,15 +114,15 @@ export function toRpcHttpCookieList(inputCookies: Cookie[]): RpcHttpCookie[] { */ function toRpcHttpCookie(inputCookie: Cookie): RpcHttpCookie { // Resolve RpcHttpCookie.SameSite enum, a one-off - let rpcSameSite: RpcHttpCookie.SameSite = RpcHttpCookie.SameSite.None; + let rpcSameSite: RpcHttpCookieSameSite = 'none'; if (inputCookie && inputCookie.sameSite) { const sameSite = inputCookie.sameSite.toLocaleLowerCase(); if (sameSite === 'lax') { - rpcSameSite = RpcHttpCookie.SameSite.Lax; + rpcSameSite = 'lax'; } else if (sameSite === 'strict') { - rpcSameSite = RpcHttpCookie.SameSite.Strict; + rpcSameSite = 'strict'; } else if (sameSite === 'none') { - rpcSameSite = RpcHttpCookie.SameSite.ExplicitNone; + rpcSameSite = 'explicitNone'; } } diff --git a/src/errors.ts b/src/errors.ts new file mode 100644 index 0000000..78e3642 --- /dev/null +++ b/src/errors.ts @@ -0,0 +1,54 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +export interface AzFuncError { + /** + * System errors can be tracked in our telemetry + * User errors cannot be tracked in our telemetry because they could have user information (users can still track it themselves in their app insights resource) + */ + isAzureFunctionsSystemError: boolean; +} + +export class AzFuncSystemError extends Error { + isAzureFunctionsSystemError = true; +} + +export class AzFuncTypeError extends TypeError implements AzFuncError { + isAzureFunctionsSystemError = true; +} + +export class AzFuncRangeError extends RangeError implements AzFuncError { + isAzureFunctionsSystemError = true; +} + +export class ReadOnlyError extends AzFuncTypeError { + constructor(propertyName: string) { + super(`Cannot assign to read only property '${propertyName}'`); + } +} + +export function ensureErrorType(err: unknown): Error & Partial { + if (err instanceof Error) { + return err; + } else { + let message: string; + if (err === undefined || err === null) { + message = 'Unknown error'; + } else if (typeof err === 'string') { + message = err; + } else if (typeof err === 'object') { + message = JSON.stringify(err); + } else { + message = String(err); + } + return new Error(message); + } +} + +/** + * This is mostly for callbacks where `null` or `undefined` indicates there is no error + * By contrast, anything thrown/caught is assumed to be an error regardless of what it is + */ +export function isError(err: unknown): boolean { + return err !== null && err !== undefined; +} diff --git a/src/http/Request.ts b/src/http/Request.ts index 1cba4d1..ac81dbe 100644 --- a/src/http/Request.ts +++ b/src/http/Request.ts @@ -11,9 +11,11 @@ import { HttpRequestUser, } from '@azure/functions'; import { RpcHttpData, RpcTypedData } from '@azure/functions-core'; -import { HeaderName } from '../constants'; +import { decode } from 'iconv-lite'; +import { HeaderName, MediaType } from '../constants'; import { fromTypedData } from '../converters/RpcConverters'; import { fromNullableMapping, fromRpcHttpBody } from '../converters/RpcHttpConverters'; +import { AzFuncSystemError } from '../errors'; import { parseForm } from '../parsers/parseForm'; import { extractHttpUserFromHeaders } from './extractHttpUserFromHeaders'; @@ -26,6 +28,7 @@ export class Request implements HttpRequest { params: HttpRequestParams; body?: any; rawBody?: any; + bufferBody?: Buffer; #cachedUser?: HttpRequestUser | null; @@ -36,8 +39,31 @@ export class Request implements HttpRequest { this.headers = fromNullableMapping(rpcHttp.nullableHeaders, rpcHttp.headers); this.query = fromNullableMapping(rpcHttp.nullableQuery, rpcHttp.query); this.params = fromNullableMapping(rpcHttp.nullableParams, rpcHttp.params); - this.body = fromTypedData(rpcHttp.body); - this.rawBody = fromRpcHttpBody(rpcHttp.body); + + if (rpcHttp.body?.bytes) { + this.bufferBody = Buffer.from(rpcHttp.body.bytes); + // We turned on the worker capability to always receive bytes instead of a string (RawHttpBodyBytes) so that we could introduce the `bufferBody` property + // However, we need to replicate the old host behavior for the `body` and `rawBody` properties so that we don't break anyone + // https://github.com/Azure/azure-functions-nodejs-worker/issues/294 + // NOTE: The tests for this are in the e2e test folder of the worker. This is so we can test the full .net host behavior of encoding/parsing/etc. + // https://github.com/Azure/azure-functions-nodejs-worker/blob/b109082f9b85b42af1de00db4192483460214d81/test/end-to-end/Azure.Functions.NodejsWorker.E2E/Azure.Functions.NodejsWorker.E2E/HttpEndToEndTests.cs + + const contentType = this.get(HeaderName.contentType)?.toLowerCase(); + let legacyBody: RpcTypedData | undefined | null; + if (contentType === MediaType.octetStream || contentType?.startsWith(MediaType.multipartPrefix)) { + // If the content type was octet or multipart, the host would leave the body as bytes + // https://github.com/Azure/azure-functions-host/blob/9ac904e34b744d95a6f746921556235d4b2b3f0f/src/WebJobs.Script.Grpc/MessageExtensions/GrpcMessageConversionExtensions.cs#L233 + legacyBody = rpcHttp.body; + } else { + // Otherwise the host would decode the buffer to a string + legacyBody = { + string: decodeBuffer(this.bufferBody), + }; + } + + this.body = fromTypedData(legacyBody); + this.rawBody = fromRpcHttpBody(legacyBody); + } } get user(): HttpRequestUser | null { @@ -55,9 +81,45 @@ export class Request implements HttpRequest { parseFormBody(): Form { const contentType = this.get(HeaderName.contentType); if (!contentType) { - throw new Error(`"${HeaderName.contentType}" header must be defined.`); + throw new AzFuncSystemError(`"${HeaderName.contentType}" header must be defined.`); } else { return parseForm(this.body, contentType); } } } + +/** + * The host used utf8 by default, but supported `detectEncodingFromByteOrderMarks` so we have to replicate that + * Host code: https://github.com/Azure/azure-webjobs-sdk-extensions/blob/03cb2ce82db74ed5a2f3299e8a84a6c35835c269/src/WebJobs.Extensions.Http/Extensions/HttpRequestExtensions.cs#L27 + * .NET code: https://github.com/dotnet/runtime/blob/e55c908229e36f99a52745d4ee85316a0e8bb6a2/src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs#L469 + * .NET description of encoding preambles: https://docs.microsoft.com/en-us/dotnet/api/system.text.encoding.getpreamble?view=net-6.0#remarks + **/ +function decodeBuffer(buffer: Buffer): string | undefined { + let encoding = 'utf8'; + if (buffer[0] === 0xfe && buffer[1] === 0xff) { + encoding = 'utf16be'; // The same as `Encoding.BigEndianUnicode` in .NET + buffer = compressBuffer(buffer, 2); + } else if (buffer[0] === 0xff && buffer[1] === 0xfe) { + if (buffer[2] !== 0 || buffer[3] !== 0) { + encoding = 'utf16le'; // The same as `Encoding.Unicode` in .NET + buffer = compressBuffer(buffer, 2); + } else { + encoding = 'utf32le'; + buffer = compressBuffer(buffer, 4); + } + } else if (buffer[0] === 0xef && buffer[1] === 0xbb && buffer[2] === 0xbf) { + encoding = 'utf8'; + buffer = compressBuffer(buffer, 3); + } else if (buffer[0] === 0 && buffer[1] === 0 && buffer[2] === 0xfe && buffer[3] === 0xff) { + encoding = 'utf32be'; + buffer = compressBuffer(buffer, 4); + } + + // NOTE: Node.js doesn't support all the above encodings by default, so we have to use "iconv-lite" to help + // Here are the iconv-lite supported encodings: https://github.com/ashtuchkin/iconv-lite/wiki/Supported-Encodings + return decode(buffer, encoding); +} + +function compressBuffer(buffer: Buffer, n: number): Buffer { + return buffer.subarray(n); +} diff --git a/src/parsers/parseForm.ts b/src/parsers/parseForm.ts index 03714d6..99bd266 100644 --- a/src/parsers/parseForm.ts +++ b/src/parsers/parseForm.ts @@ -3,6 +3,7 @@ import * as types from '@azure/functions'; import { MediaType } from '../constants'; +import { AzFuncSystemError } from '../errors'; import { parseContentType } from './parseHeader'; import { parseMultipartForm } from './parseMultipartForm'; @@ -26,7 +27,7 @@ export function parseForm(data: Buffer | string, contentType: string): Form { return new Form(parts); } default: - throw new Error( + throw new AzFuncSystemError( `Media type "${mediaType}" does not match types supported for form parsing: "${MediaType.multipartForm}", "${MediaType.urlEncodedForm}".` ); } diff --git a/src/parsers/parseHeader.ts b/src/parsers/parseHeader.ts index dbafe8b..d8d175f 100644 --- a/src/parsers/parseHeader.ts +++ b/src/parsers/parseHeader.ts @@ -2,6 +2,7 @@ // Licensed under the MIT License. import { HeaderName } from '../constants'; +import { AzFuncSystemError } from '../errors'; const space = ' '; // See "LEXICAL TOKENS" section for definition of ctl chars and quoted string: https://www.w3.org/Protocols/rfc822/3_Lexical.html @@ -35,7 +36,7 @@ export function getHeaderValue(data: string, headerName: string): string | null export function parseContentType(data: string): [string, HeaderParams] { const match = new RegExp(`${start}(${token}\\/${token})${semicolonEnd}`, 'i').exec(data); if (!match) { - throw new Error(`${HeaderName.contentType} must begin with format "type/subtype".`); + throw new AzFuncSystemError(`${HeaderName.contentType} must begin with format "type/subtype".`); } else { return [match[1], parseHeaderParams(match[2])]; } @@ -48,7 +49,7 @@ export function parseContentType(data: string): [string, HeaderParams] { export function parseContentDisposition(data: string): [string, HeaderParams] { const match = new RegExp(`${start}(${token})${semicolonEnd}`, 'i').exec(data); if (!match) { - throw new Error(`${HeaderName.contentDisposition} must begin with disposition type.`); + throw new AzFuncSystemError(`${HeaderName.contentDisposition} must begin with disposition type.`); } else { return [match[1], parseHeaderParams(match[2])]; } @@ -81,7 +82,7 @@ export class HeaderParams { get(name: string): string { const result = this.#params[name.toLowerCase()]; if (result === undefined) { - throw new Error(`Failed to find parameter with name "${name}".`); + throw new AzFuncSystemError(`Failed to find parameter with name "${name}".`); } else { return result; } diff --git a/src/parsers/parseMultipartForm.ts b/src/parsers/parseMultipartForm.ts index d6ab103..0c27064 100644 --- a/src/parsers/parseMultipartForm.ts +++ b/src/parsers/parseMultipartForm.ts @@ -3,6 +3,7 @@ import { FormPart } from '@azure/functions'; import { HeaderName } from '../constants'; +import { AzFuncSystemError } from '../errors'; import { getHeaderValue, parseContentDisposition } from './parseHeader'; const carriageReturn = Buffer.from('\r')[0]; @@ -50,7 +51,7 @@ export function parseMultipartForm(chunk: Buffer, boundary: string): [string, Fo inHeaders = true; } else if (inHeaders) { if (!currentPart) { - throw new Error(`Expected form data to start with boundary "${boundary}".`); + throw new AzFuncSystemError(`Expected form data to start with boundary "${boundary}".`); } const lineAsString = line.toString(); @@ -58,7 +59,7 @@ export function parseMultipartForm(chunk: Buffer, boundary: string): [string, Fo // A blank line means we're done with the headers for this part inHeaders = false; if (!currentName) { - throw new Error( + throw new AzFuncSystemError( `Expected part to have header "${HeaderName.contentDisposition}" with parameter "name".` ); } else { diff --git a/src/utils/InternalException.ts b/src/utils/InternalException.ts deleted file mode 100644 index 6fcefeb..0000000 --- a/src/utils/InternalException.ts +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT License. - -export class InternalException extends Error { - isAzureFunctionsInternalException = true; -} diff --git a/src/utils/ensureErrorType.ts b/src/utils/ensureErrorType.ts deleted file mode 100644 index c15f423..0000000 --- a/src/utils/ensureErrorType.ts +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT License. - -export interface AzFuncError extends Error { - isAzureFunctionsInternalException?: boolean; -} - -export function ensureErrorType(err: unknown): AzFuncError { - if (err instanceof Error) { - return err; - } else { - let message: string; - if (err === undefined || err === null) { - message = 'Unknown error'; - } else if (typeof err === 'string') { - message = err; - } else if (typeof err === 'object') { - message = JSON.stringify(err); - } else { - message = String(err); - } - return new Error(message); - } -} - -/** - * This is mostly for callbacks where `null` or `undefined` indicates there is no error - * By contrast, anything thrown/caught is assumed to be an error regardless of what it is - */ -export function isError(err: unknown): boolean { - return err !== null && err !== undefined; -} diff --git a/src/utils/nonNull.ts b/src/utils/nonNull.ts index 231fabc..9fcdf31 100644 --- a/src/utils/nonNull.ts +++ b/src/utils/nonNull.ts @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. -import { InternalException } from './InternalException'; +import { AzFuncSystemError } from '../errors'; /** * Retrieves a property by name from an object and checks that it's not null and not undefined. It is strongly typed @@ -20,7 +20,7 @@ export function nonNullProp( */ export function nonNullValue(value: T | undefined, propertyNameOrMessage?: string): T { if (value === null || value === undefined) { - throw new InternalException( + throw new AzFuncSystemError( 'Internal error: Expected value to be neither null nor undefined' + (propertyNameOrMessage ? `: ${propertyNameOrMessage}` : '') ); diff --git a/test/Context.test.ts b/test/Context.test.ts index 65e4af5..b850b4f 100644 --- a/test/Context.test.ts +++ b/test/Context.test.ts @@ -44,8 +44,8 @@ describe('Context', () => { bindings: { myTimer: { type: 'timerTrigger', - direction: 0, - dataType: 0, + direction: 'in', + dataType: 'undefined', }, }, }); @@ -70,8 +70,8 @@ describe('Context', () => { bindings: { req: { type: 'http', - direction: 0, - dataType: 1, + direction: 'in', + dataType: 'string', }, }, }); @@ -104,8 +104,8 @@ describe('Context', () => { bindings: { req: { type: 'http', - direction: 0, - dataType: 1, + direction: 'in', + dataType: 'string', }, }, }); @@ -157,8 +157,8 @@ describe('Context', () => { bindings: { req: { type: 'http', - direction: 0, - dataType: 1, + direction: 'in', + dataType: 'string', }, }, }); @@ -201,8 +201,8 @@ describe('Context', () => { bindings: { req: { type: 'http', - direction: 0, - dataType: 1, + direction: 'in', + dataType: 'string', }, }, }); diff --git a/test/FunctionInfo.test.ts b/test/FunctionInfo.test.ts index ca020d7..e085cbb 100644 --- a/test/FunctionInfo.test.ts +++ b/test/FunctionInfo.test.ts @@ -13,13 +13,13 @@ describe('FunctionInfo', () => { bindings: { req: { type: 'httpTrigger', - direction: 0, - dataType: 1, + direction: 'in', + dataType: 'string', }, $return: { type: 'http', - direction: 1, - dataType: 1, + direction: 'out', + dataType: 'string', }, }, }; @@ -33,8 +33,8 @@ describe('FunctionInfo', () => { bindings: { req: { type: 'httpTrigger', - direction: 0, - dataType: 1, + direction: 'in', + dataType: 'string', }, }, }; @@ -49,13 +49,13 @@ describe('FunctionInfo', () => { bindings: { input: { type: 'queue', - direction: 0, - dataType: 1, + direction: 'in', + dataType: 'string', }, $return: { type: 'queue', - direction: 1, - dataType: 1, + direction: 'out', + dataType: 'string', }, }, }; diff --git a/test/Types.test.ts b/test/Types.test.ts index 1e58961..199f6bd 100644 --- a/test/Types.test.ts +++ b/test/Types.test.ts @@ -17,9 +17,9 @@ describe('Public TypeScript types', () => { }); async function runTsBuild(tsVersion: string): Promise { - const repoRoot = path.join(__dirname, '..', '..'); + const repoRoot = path.join(__dirname, '..'); const tscPath = path.join(repoRoot, 'node_modules', `typescript${tsVersion}`, 'bin', 'tsc'); - const projectFile = path.join(repoRoot, 'types', 'tsconfig.json'); + const projectFile = path.join(repoRoot, 'test', 'types', 'tsconfig.json'); return new Promise((resolve, reject) => { const cmd = cp.spawn('node', [tscPath, '--project', projectFile]); cmd.stdout.on('data', function (data) { diff --git a/test/converters/BindingConverters.test.ts b/test/converters/BindingConverters.test.ts index 45196cc..dc742c0 100644 --- a/test/converters/BindingConverters.test.ts +++ b/test/converters/BindingConverters.test.ts @@ -1,18 +1,17 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. -import { RpcBindingInfo, RpcFunctionMetadata, RpcInvocationRequest, RpcTypedData } from '@azure/functions-core'; +import { RpcFunctionMetadata, RpcInvocationRequest, RpcTypedData } from '@azure/functions-core'; import { expect } from 'chai'; import { fromString } from 'long'; import 'mocha'; import { getBindingDefinitions, getNormalizedBindingData } from '../../src/converters/BindingConverters'; import { fromTypedData } from '../../src/converters/RpcConverters'; -import { toRpcHttp } from '../../src/converters/RpcHttpConverters'; import { FunctionInfo } from '../../src/FunctionInfo'; describe('Binding Converters', () => { it('normalizes binding trigger metadata for HTTP', () => { - const mockRequest: RpcTypedData = toRpcHttp({ url: 'https://mock' }); + const mockRequest: RpcTypedData = { http: { url: 'https://mock' } }; const triggerDataMock: { [k: string]: RpcTypedData } = { Headers: { json: JSON.stringify({ Connection: 'Keep-Alive' }), @@ -110,6 +109,23 @@ describe('Binding Converters', () => { expect(bindingData.sys.UtcNow).to.be.undefined; }); + it('normalizes binding trigger metadata with bytes as number', () => { + // Test to cover this bug: + // https://github.com/Azure/azure-functions-nodejs-worker/issues/607 + const request: RpcInvocationRequest = { + triggerMetadata: { + A: { + data: 'json', + json: '{"B":{"bytes":4}}', + }, + }, + invocationId: '12341', + }; + + const bindingData = getNormalizedBindingData(request); + expect(bindingData.a).to.deep.equal({ b: { bytes: 4 } }); + }); + it('catologues binding definitions', () => { const functionMetaData: RpcFunctionMetadata = { name: 'MyFunction', @@ -118,15 +134,15 @@ describe('Binding Converters', () => { bindings: { req: { type: 'httpTrigger', - direction: RpcBindingInfo.Direction.in, + direction: 'in', }, res: { type: 'http', - direction: RpcBindingInfo.Direction.out, + direction: 'out', }, firstQueueOutput: { type: 'queue', - direction: RpcBindingInfo.Direction.out, + direction: 'out', }, noDirection: { type: 'queue', diff --git a/test/converters/RpcHttpConverters.test.ts b/test/converters/RpcHttpConverters.test.ts index 0c5df45..574f241 100644 --- a/test/converters/RpcHttpConverters.test.ts +++ b/test/converters/RpcHttpConverters.test.ts @@ -1,10 +1,10 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. -import { Cookie } from '@azure/functions'; -import { RpcHttpCookie } from '@azure/functions-core'; +import { Cookie, HttpResponse } from '@azure/functions'; import { expect } from 'chai'; import 'mocha'; +import { toTypedData } from '../../src/converters/RpcConverters'; import { toRpcHttp, toRpcHttpCookieList } from '../../src/converters/RpcHttpConverters'; describe('Rpc Converters', () => { @@ -69,16 +69,16 @@ describe('Rpc Converters', () => { const rpcCookies = toRpcHttpCookieList(cookieInputs); expect(rpcCookies[0].name).to.equal('none-cookie'); - expect(rpcCookies[0].sameSite).to.equal(RpcHttpCookie.SameSite.ExplicitNone); + expect(rpcCookies[0].sameSite).to.equal('explicitNone'); expect(rpcCookies[1].name).to.equal('lax-cookie'); - expect(rpcCookies[1].sameSite).to.equal(RpcHttpCookie.SameSite.Lax); + expect(rpcCookies[1].sameSite).to.equal('lax'); expect(rpcCookies[2].name).to.equal('strict-cookie'); - expect(rpcCookies[2].sameSite).to.equal(RpcHttpCookie.SameSite.Strict); + expect(rpcCookies[2].sameSite).to.equal('strict'); expect(rpcCookies[3].name).to.equal('default-cookie'); - expect(rpcCookies[3].sameSite).to.equal(RpcHttpCookie.SameSite.None); + expect(rpcCookies[3].sameSite).to.equal('none'); }); it('throws on invalid input', () => { @@ -128,4 +128,13 @@ describe('Rpc Converters', () => { "The HTTP response must be an 'object' type that can include properties such as 'body', 'status', and 'headers'. Learn more: https://go.microsoft.com/fwlink/?linkid=2112563" ); }); + + it('copies by value', () => { + const response: HttpResponse = { + body: 'before', + }; + const converted = toRpcHttp(response); + response.body = 'after'; + expect(converted.http?.body).to.deep.equal(toTypedData('before')); + }); }); diff --git a/test/utils/ensureErrorType.test.ts b/test/errors.test.ts similarity index 93% rename from test/utils/ensureErrorType.test.ts rename to test/errors.test.ts index 6fce578..fe0f01d 100644 --- a/test/utils/ensureErrorType.test.ts +++ b/test/errors.test.ts @@ -3,9 +3,9 @@ import { expect } from 'chai'; import 'mocha'; -import { ensureErrorType } from '../../src/utils/ensureErrorType'; +import { ensureErrorType } from '../src/errors'; -describe('ensureErrorType', () => { +describe('errors', () => { it('null', () => { validateError(ensureErrorType(null), 'Unknown error'); }); diff --git a/test/index.ts b/test/index.ts index 4c17b44..36c9858 100644 --- a/test/index.ts +++ b/test/index.ts @@ -4,34 +4,37 @@ import * as globby from 'globby'; import * as Mocha from 'mocha'; import * as path from 'path'; -import { setupTestCoreApi } from './setupTestCoreApi'; export async function run(): Promise { - setupTestCoreApi(); - - const options: Mocha.MochaOptions = { - color: true, - reporter: 'mocha-multi-reporters', - reporterOptions: { - reporterEnabled: 'spec, mocha-junit-reporter', - mochaJunitReporterReporterOptions: { - mochaFile: path.resolve(__dirname, '..', '..', 'test', 'unit-test-results.xml'), + try { + const options: Mocha.MochaOptions = { + color: true, + require: ['ts-node/register'], + reporter: 'mocha-multi-reporters', + reporterOptions: { + reporterEnabled: 'spec, mocha-junit-reporter', + mochaJunitReporterReporterOptions: { + mochaFile: path.resolve(__dirname, '..', 'test', 'unit-test-results.xml'), + }, }, - }, - }; + }; - addEnvVarsToMochaOptions(options); - console.log(`Mocha options: ${JSON.stringify(options, undefined, 2)}`); + addEnvVarsToMochaOptions(options); + console.log(`Mocha options: ${JSON.stringify(options, undefined, 2)}`); - const mocha = new Mocha(options); + const mocha = new Mocha(options); - const files: string[] = await globby('**/**.test.js', { cwd: __dirname }); + const files: string[] = await globby('**/**.test.ts', { cwd: __dirname }); - files.forEach((f) => mocha.addFile(path.resolve(__dirname, f))); + files.forEach((f) => mocha.addFile(path.resolve(__dirname, f))); - const failures = await new Promise((resolve) => mocha.run(resolve)); - if (failures > 0) { - throw new Error(`${failures} tests failed.`); + const failures = await new Promise((resolve) => mocha.run(resolve)); + if (failures > 0) { + throw new Error(`${failures} tests failed.`); + } + } catch (err) { + console.error('Test run failed'); + process.exit(1); } } diff --git a/test/setupTestCoreApi.ts b/test/setupTestCoreApi.ts deleted file mode 100644 index 2247d1f..0000000 --- a/test/setupTestCoreApi.ts +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the MIT License. - -import Module = require('module'); - -export function setupTestCoreApi(): void { - const coreApi = { - RpcLog: { Level, RpcLogCategory }, - RpcHttpCookie: { SameSite }, - RpcBindingInfo: { Direction, DataType }, - }; - - Module.prototype.require = new Proxy(Module.prototype.require, { - apply(target, thisArg, argArray) { - if (argArray[0] === '@azure/functions-core') { - return coreApi; - } else { - return Reflect.apply(target, thisArg, argArray); - } - }, - }); -} - -enum Level { - Trace = 0, - Debug = 1, - Information = 2, - Warning = 3, - Error = 4, - Critical = 5, - None = 6, -} - -enum RpcLogCategory { - User = 0, - System = 1, - CustomMetric = 2, -} - -enum SameSite { - None = 0, - Lax = 1, - Strict = 2, - ExplicitNone = 3, -} - -enum Direction { - in = 0, - out = 1, - inout = 2, -} - -enum DataType { - undefined = 0, - string = 1, - binary = 2, - stream = 3, -} diff --git a/types/index.test.ts b/test/types/index.test.ts similarity index 99% rename from types/index.test.ts rename to test/types/index.test.ts index 8d15763..15315c1 100644 --- a/types/index.test.ts +++ b/test/types/index.test.ts @@ -22,6 +22,7 @@ const runHttp: AzureFunction = async function (context: Context, req: HttpReques context.log("This is a 'GET' method"); } + context.log(`Header: ${req.get('X-CUSTOM-HEADER')}`); context.log('JavaScript HTTP trigger function processed a request.'); if (req.query.name || (req.body && req.body.name)) { context.res = { diff --git a/test/types/tsconfig.json b/test/types/tsconfig.json new file mode 100644 index 0000000..78f0c33 --- /dev/null +++ b/test/types/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "strict": true, + "outDir": "dist", + "baseUrl": "./", + "paths": { + "@azure/functions": [ + "../../types" + ] + } + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 4422217..3fd983d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,7 +5,7 @@ "noImplicitAny": false, "strict": true, "noUnusedLocals": true, - "outDir": "dist", + "outDir": "out", "sourceMap": true, "baseUrl": "./", "paths": { diff --git a/types-core/index.d.ts b/types-core/index.d.ts index 30713ed..cf28299 100644 --- a/types-core/index.d.ts +++ b/types-core/index.d.ts @@ -10,6 +10,32 @@ declare module '@azure/functions-core' { */ const version: string; + /** + * The version of the Functions Host + */ + const hostVersion: string; + + /** + * Register a function + * This is a preview feature and requires the feature flag `EnableWorkerIndexing` to be set in the app setting `AzureWebJobsFeatureFlags` + */ + function registerFunction(metadata: FunctionMetadata, callback: FunctionCallback): Disposable; + + /** + * A slimmed down version of `RpcFunctionMetadata` that includes the minimum amount of information needed to register a function + */ + interface FunctionMetadata { + /** + * The function name + */ + name: string; + + /** + * A dictionary of binding name to binding info + */ + bindings: { [name: string]: RpcBindingInfo }; + } + /** * Register a hook to interact with the lifecycle of Azure Functions. * Hooks are executed in the order they were registered and will block execution if they throw an error @@ -32,12 +58,14 @@ declare module '@azure/functions-core' { interface HookContext { /** * The recommended place to share data between hooks in the same scope (app-level vs invocation-level) + * This object is readonly and attempting to overwrite it will throw an error */ - hookData: HookData; + readonly hookData: HookData; /** * The recommended place to share data across scopes for all hooks + * This object is readonly and attempting to overwrite it will throw an error */ - appHookData: HookData; + readonly appHookData: HookData; } /** @@ -96,10 +124,6 @@ declare module '@azure/functions-core' { * Absolute directory of the function app */ functionAppDirectory: string; - /** - * The version of the host running the function app - */ - hostVersion: string; } /** @@ -189,7 +213,7 @@ declare module '@azure/functions-core' { /** * The recommended way to log information */ - log(level: RpcLog.Level, category: RpcLog.RpcLogCategory, message: string): void; + log(level: RpcLogLevel, category: RpcLogCategory, message: string): void; } type InvocationState = 'preInvocationHooks' | 'postInvocationHooks' | 'invocation'; @@ -262,7 +286,7 @@ declare module '@azure/functions-core' { } interface RpcStatusResult { - status?: RpcStatusResult.Status | null; + status?: RpcStatus | null; result?: string | null; @@ -271,20 +295,14 @@ declare module '@azure/functions-core' { logs?: RpcLog[] | null; } - namespace RpcStatusResult { - enum Status { - Failure = 0, - Success = 1, - Cancelled = 2, - } - } + type RpcStatus = 'failure' | 'success' | 'cancelled'; interface RpcLog { invocationId?: string | null; category?: string | null; - level?: RpcLog.Level | null; + level?: RpcLogLevel | null; message?: string | null; @@ -292,26 +310,12 @@ declare module '@azure/functions-core' { exception?: RpcException | null; - logCategory?: RpcLog.RpcLogCategory | null; + logCategory?: RpcLogCategory | null; } - namespace RpcLog { - enum Level { - Trace = 0, - Debug = 1, - Information = 2, - Warning = 3, - Error = 4, - Critical = 5, - None = 6, - } + type RpcLogLevel = 'trace' | 'debug' | 'information' | 'warning' | 'error' | 'critical' | 'none'; - enum RpcLogCategory { - User = 0, - System = 1, - CustomMetric = 2, - } - } + type RpcLogCategory = 'user' | 'system' | 'customMetric'; interface RpcException { source?: string | null; @@ -324,25 +328,14 @@ declare module '@azure/functions-core' { interface RpcBindingInfo { type?: string | null; - direction?: RpcBindingInfo.Direction | null; + direction?: RpcBindingDirection | null; - dataType?: RpcBindingInfo.DataType | null; + dataType?: RpcBindingDataType | null; } - namespace RpcBindingInfo { - enum Direction { - in = 0, - out = 1, - inout = 2, - } + type RpcBindingDirection = 'in' | 'out' | 'inout'; - enum DataType { - undefined = 0, - string = 1, - binary = 2, - stream = 3, - } - } + type RpcBindingDataType = 'undefined' | 'string' | 'binary' | 'stream'; interface RpcTypedData { string?: string | null; @@ -473,7 +466,7 @@ declare module '@azure/functions-core' { httpOnly?: RpcNullableBool | null; - sameSite?: RpcHttpCookie.SameSite | null; + sameSite?: RpcHttpCookieSameSite | null; maxAge?: RpcNullableDouble | null; } @@ -500,13 +493,6 @@ declare module '@azure/functions-core' { nanos?: number | null; } - namespace RpcHttpCookie { - enum SameSite { - None = 0, - Lax = 1, - Strict = 2, - ExplicitNone = 3, - } - } + type RpcHttpCookieSameSite = 'none' | 'lax' | 'strict' | 'explicitNone'; // #endregion rpc types } diff --git a/types/Context.d.ts b/types/Context.d.ts new file mode 100644 index 0000000..9e389b3 --- /dev/null +++ b/types/Context.d.ts @@ -0,0 +1,192 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +import { HttpRequest } from './http'; + +/** + * The context object can be used for writing logs, reading data from bindings, setting outputs and using + * the context.done callback when your exported function is synchronous. A context object is passed + * to your function from the Azure Functions runtime on function invocation. + */ +export interface Context { + /** + * A unique GUID per function invocation. + */ + invocationId: string; + /** + * Function execution metadata. + */ + executionContext: ExecutionContext; + /** + * Input and trigger binding data, as defined in function.json. Properties on this object are dynamically + * generated and named based off of the "name" property in function.json. + */ + bindings: ContextBindings; + /** + * Trigger metadata and function invocation data. + */ + bindingData: ContextBindingData; + /** + * TraceContext information to enable distributed tracing scenarios. + */ + traceContext: TraceContext; + /** + * Bindings your function uses, as defined in function.json. + */ + bindingDefinitions: BindingDefinition[]; + /** + * Allows you to write streaming function logs. Calling directly allows you to write streaming function logs + * at the default trace level. + */ + log: Logger; + /** + * A callback function that signals to the runtime that your code has completed. If your function is synchronous, + * you must call context.done at the end of execution. If your function is asynchronous, you should not use this + * callback. + * + * @param err A user-defined error to pass back to the runtime. If present, your function execution will fail. + * @param result An object containing output binding data. `result` will be passed to JSON.stringify unless it is + * a string, Buffer, ArrayBufferView, or number. + * + * @deprecated Use of sync functions with `context.done()` is not recommended. Use async/await and pass the response as the return value instead. + * See the docs here for more information: https://aka.ms/functions-js-async-await + */ + done(err?: Error | string | null, result?: any): void; + /** + * HTTP request object. Provided to your function when using HTTP Bindings. + */ + req?: HttpRequest; + /** + * HTTP response object. Provided to your function when using HTTP Bindings. + */ + res?: { + [key: string]: any; + }; + /** + * If this flag is set to true in your function, the error for calling `context.done()` within + * an async function will not be logged. More info: https://go.microsoft.com/fwlink/?linkid=2097909 + * @default false + */ + suppressAsyncDoneError?: boolean; +} + +/** + * Context bindings object. Provided to your function binding data, as defined in function.json. + */ +export interface ContextBindings { + [name: string]: any; +} + +/** + * Context binding data. Provided to your function trigger metadata and function invocation data. + */ +export interface ContextBindingData { + /** + * A unique GUID per function invocation. + */ + invocationId: string; + + [name: string]: any; +} + +export interface ExecutionContext { + /** + * A unique GUID per function invocation. + */ + invocationId: string; + /** + * The name of the function that is being invoked. The name of your function is always the same as the + * name of the corresponding function.json's parent directory. + */ + functionName: string; + /** + * The directory your function is in (this is the parent directory of this function's function.json). + */ + functionDirectory: string; + /** + * The retry context of the current function execution or null if the retry policy is not defined. + */ + retryContext: RetryContext | null; +} + +export interface RetryContext { + /** + * Current retry count of the function executions. + */ + retryCount: number; + /** + * Max retry count is the maximum number of times an execution is retried before eventual failure. A value of -1 means to retry indefinitely. + */ + maxRetryCount: number; + /** + * Exception that caused the retry + */ + exception?: Exception; +} + +export interface Exception { + /** Exception source */ + source?: string | null; + /** Exception stackTrace */ + stackTrace?: string | null; + /** Exception message */ + message?: string | null; +} + +/** + * TraceContext information to enable distributed tracing scenarios. + */ +export interface TraceContext { + /** Describes the position of the incoming request in its trace graph in a portable, fixed-length format. */ + traceparent: string | null | undefined; + /** Extends traceparent with vendor-specific data. */ + tracestate: string | null | undefined; + /** Holds additional properties being sent as part of request telemetry. */ + attributes: + | { + [k: string]: string; + } + | null + | undefined; +} + +export interface BindingDefinition { + /** + * The name of your binding, as defined in function.json. + */ + name: string; + /** + * The type of your binding, as defined in function.json. + */ + type: string; + /** + * The direction of your binding, as defined in function.json. + */ + direction: 'in' | 'out' | 'inout' | undefined; +} + +/** + * Allows you to write streaming function logs. + */ +export interface Logger { + /** + * Writes streaming function logs at the default trace level. + */ + (...args: any[]): void; + /** + * Writes to error level logging or lower. + */ + error(...args: any[]): void; + /** + * Writes to warning level logging or lower. + */ + warn(...args: any[]): void; + /** + * Writes to info level logging or lower. + */ + info(...args: any[]): void; + /** + * Writes to verbose level logging. + */ + verbose(...args: any[]): void; +} diff --git a/types/http.d.ts b/types/http.d.ts new file mode 100644 index 0000000..7d9bb79 --- /dev/null +++ b/types/http.d.ts @@ -0,0 +1,339 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +/** + * HTTP request headers. + */ +export interface HttpRequestHeaders { + [name: string]: string; +} + +/** + * HTTP response headers. + */ +export interface HttpResponseHeaders { + [name: string]: string; +} + +/** + * Query string parameter keys and values from the URL. + */ +export interface HttpRequestQuery { + [name: string]: string; +} + +/** + * Route parameter keys and values. + */ +export interface HttpRequestParams { + [name: string]: string; +} + +/** + * Object representing logged-in user, either through + * AppService/Functions authentication, or SWA Authentication + */ +export interface HttpRequestUser { + /** + * Type of authentication, either AppService or StaticWebApps + */ + type: HttpRequestUserType; + /** + * unique user GUID + */ + id: string; + /** + * unique username + */ + username: string; + /** + * provider of authentication service + */ + identityProvider: string; + /** + * Extra authentication information, dependent on auth type + * and auth provider + */ + claimsPrincipalData: { + [key: string]: any; + }; +} + +/** + * HTTP request object. Provided to your function when using HTTP Bindings. + */ +export interface HttpRequest { + /** + * HTTP request method used to invoke this function. + */ + method: HttpMethod | null; + /** + * Request URL. + */ + url: string; + /** + * HTTP request headers. + */ + headers: HttpRequestHeaders; + /** + * Query string parameter keys and values from the URL. + */ + query: HttpRequestQuery; + /** + * Route parameter keys and values. + */ + params: HttpRequestParams; + /** + * Object representing logged-in user, either through + * AppService/Functions authentication, or SWA Authentication + * null when no such user is logged in. + */ + user: HttpRequestUser | null; + /** + * The HTTP request body. + * If the media type is 'application/octet-stream' or 'multipart/*', this will be a Buffer + * If the value is a JSON parse-able string, this will be the parsed object + * Otherwise, this will be a string + */ + body?: any; + + /** + * The HTTP request body as a UTF-8 string. In this case, the name "raw" is used because the string will never be parsed to an object even if it is json. + * Improvements to the naming are tracked in https://github.com/Azure/azure-functions-nodejs-worker/issues/294 + */ + rawBody?: any; + + /** + * The raw Buffer representing the body before any decoding or parsing has been done + */ + bufferBody?: Buffer; + + /** + * Get the value of a particular header field + */ + get(field: string): string | undefined; + + /** + * Parses the body and returns an object representing a form + * @throws if the content type is not "multipart/form-data" or "application/x-www-form-urlencoded" + */ + parseFormBody(): Form; +} + +export interface Form extends Iterable<[string, FormPart]> { + /** + * Returns the value of the first name-value pair whose name is `name`. If there are no such pairs, `null` is returned. + */ + get(name: string): FormPart | null; + + /** + * Returns the values of all name-value pairs whose name is `name`. If there are no such pairs, an empty array is returned. + */ + getAll(name: string): FormPart[]; + + /** + * Returns `true` if there is at least one name-value pair whose name is `name`. + */ + has(name: string): boolean; + + /** + * The number of parts in this form + */ + length: number; +} + +export interface FormPart { + /** + * The value for this part of the form + */ + value: Buffer; + + /** + * The file name for this part of the form, if specified + */ + fileName?: string; + + /** + * The content type for this part of the form, assumed to be "text/plain" if not specified + */ + contentType?: string; +} + +/** + * Possible values for an HTTP request method. + */ +export type HttpMethod = 'GET' | 'POST' | 'DELETE' | 'HEAD' | 'PATCH' | 'PUT' | 'OPTIONS' | 'TRACE' | 'CONNECT'; + +/** + * Possible values for an HTTP Request user type + */ +export type HttpRequestUserType = 'AppService' | 'StaticWebApps'; + +/** + * Http response object and methods. + * This is the default of the res property in the Context object provided to your function when using HTTP triggers. + */ +export interface HttpResponseFull { + /** + * HTTP response headers. + */ + headers?: HttpResponseHeaders; + /** + * HTTP response cookies. + */ + cookies?: Cookie[]; + /** + * HTTP response body. + */ + body?: any; + /** + * HTTP response status code. + * @default 200 + */ + statusCode?: number | string; + /** + * Enable content negotiation of response body if true + * If false, treat response body as raw + * @default false + */ + enableContentNegotiation?: boolean; + /** + * Sets the HTTP response status code + * @returns the updated HttpResponseFull instance + */ + status: (statusCode: number | string) => HttpResponseFull; + /** + * Sets a particular header field to a value + * @returns the updated HttpResponseFull instance + */ + setHeader(field: string, val: any): HttpResponseFull; + /** + * Has the same functionality as setHeader. + * Sets a particular header field to a value + * @returns the updated HttpResponseFull instance + */ + header(field: string, val: any): HttpResponseFull; + /** + * Has the same functionality as setHeader. + * Sets a particular header field to a value + * @returns the updated HttpResponseFull instance + */ + set(field: string, val: any): HttpResponseFull; + /** + * Get the value of a particular header field + */ + getHeader(field: string): any; + /** + * Has the same functionality as getHeader + * Get the value of a particular header field + */ + get(field: string): any; + /** + * Removes a particular header field + * @returns the updated HttpResponseFull instance + */ + removeHeader(field: string): HttpResponseFull; + /** + * Set the 'Content-Type' header to a particular value + * @returns the updated HttpResponseFull instance + */ + type(type: string): HttpResponseFull; + /** + * Automatically sets the content-type then calls context.done() + * @returns updated HttpResponseFull instance + * @deprecated this method calls context.done() which is deprecated, use async/await and pass the response as the return value instead. + * See the docs here for more information: https://aka.ms/functions-js-async-await + */ + send(body?: any): HttpResponseFull; + /** + * Same as send() + * Automatically sets the content-type then calls context.done() + * @returns updated HttpResponseFull instance + * @deprecated this method calls context.done() which is deprecated, use async/await and pass the response as your function's return value instead. + * See the docs here for more information: https://aka.ms/functions-js-async-await + */ + end(body?: any): HttpResponseFull; + /** + * Sets the status code then calls send() + * @returns updated HttpResponseFull instance + * @deprecated this method calls context.done() which is deprecated, use async/await and pass the response as your function's return value instead. + * See the docs here for more information: https://aka.ms/functions-js-async-await + */ + sendStatus(statusCode: string | number): HttpResponseFull; + /** + * Sets the 'Content-Type' header to 'application/json' then calls send(body) + * @deprecated this method calls context.done() which is deprecated, use async/await and pass the response as your function's return value instead. + * See the docs here for more information: https://aka.ms/functions-js-async-await + */ + json(body?: any): void; +} + +/** + * Http response object. + * This is not the default on the Context object, but you may replace context.res with an object of this type when using HTTP triggers. + */ +export interface HttpResponseSimple { + /** + * HTTP response headers. + */ + headers?: HttpResponseHeaders; + /** + * HTTP response cookies. + */ + cookies?: Cookie[]; + /** + * HTTP response body. + */ + body?: any; + /** + * HTTP response status code. + * This property takes precedence over the `status` property + * @default 200 + */ + statusCode?: number | string; + /** + * HTTP response status code + * The same as `statusCode`. This property is ignored if `statusCode` is set + * @default 200 + */ + status?: number | string; + /** + * Enable content negotiation of response body if true + * If false, treat response body as raw + * @default false + */ + enableContentNegotiation?: boolean; +} + +/** + * Http response type. + */ +export type HttpResponse = HttpResponseSimple | HttpResponseFull; + +/** + * Http response cookie object to "Set-Cookie" + */ +export interface Cookie { + /** Cookie name */ + name: string; + /** Cookie value */ + value: string; + /** Specifies allowed hosts to receive the cookie */ + domain?: string; + /** Specifies URL path that must exist in the requested URL */ + path?: string; + /** + * NOTE: It is generally recommended that you use maxAge over expires. + * Sets the cookie to expire at a specific date instead of when the client closes. + * This can be a Javascript Date or Unix time in milliseconds. + */ + expires?: Date | number; + /** Sets the cookie to only be sent with an encrypted request */ + secure?: boolean; + /** Sets the cookie to be inaccessible to JavaScript's Document.cookie API */ + httpOnly?: boolean; + /** Can restrict the cookie to not be sent with cross-site requests */ + sameSite?: 'Strict' | 'Lax' | 'None' | undefined; + /** Number of seconds until the cookie expires. A zero or negative number will expire the cookie immediately. */ + maxAge?: number; +} diff --git a/types/index.d.ts b/types/index.d.ts index ff20287..56d0995 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,537 +1,26 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the MIT License. -declare module '@azure/functions' { - /** - * Sets the programming model contained in this package to be the one used by the Azure Functions worker - */ - function setup(): void; - - /** - * Interface for your Azure Function code. This function must be exported (via module.exports or exports) - * and will execute when triggered. It is recommended that you declare this function as async, which - * implicitly returns a Promise. - * @param context Context object passed to your function from the Azure Functions runtime. - * @param {any[]} args Optional array of input and trigger binding data. These binding data are passed to the - * function in the same order that they are defined in function.json. Valid input types are string, HttpRequest, - * and Buffer. - * @returns Output bindings (optional). If you are returning a result from a Promise (or an async function), this - * result will be passed to JSON.stringify unless it is a string, Buffer, ArrayBufferView, or number. - */ - export type AzureFunction = (context: Context, ...args: any[]) => Promise | void; - - /** - * Context bindings object. Provided to your function binding data, as defined in function.json. - */ - export interface ContextBindings { - [name: string]: any; - } - /** - * Context binding data. Provided to your function trigger metadata and function invocation data. - */ - export interface ContextBindingData { - /** - * A unique GUID per function invocation. - */ - invocationId: string; - - [name: string]: any; - } - /** - * The context object can be used for writing logs, reading data from bindings, setting outputs and using - * the context.done callback when your exported function is synchronous. A context object is passed - * to your function from the Azure Functions runtime on function invocation. - */ - export interface Context { - /** - * A unique GUID per function invocation. - */ - invocationId: string; - /** - * Function execution metadata. - */ - executionContext: ExecutionContext; - /** - * Input and trigger binding data, as defined in function.json. Properties on this object are dynamically - * generated and named based off of the "name" property in function.json. - */ - bindings: ContextBindings; - /** - * Trigger metadata and function invocation data. - */ - bindingData: ContextBindingData; - /** - * TraceContext information to enable distributed tracing scenarios. - */ - traceContext: TraceContext; - /** - * Bindings your function uses, as defined in function.json. - */ - bindingDefinitions: BindingDefinition[]; - /** - * Allows you to write streaming function logs. Calling directly allows you to write streaming function logs - * at the default trace level. - */ - log: Logger; - /** - * A callback function that signals to the runtime that your code has completed. If your function is synchronous, - * you must call context.done at the end of execution. If your function is asynchronous, you should not use this - * callback. - * - * @param err A user-defined error to pass back to the runtime. If present, your function execution will fail. - * @param result An object containing output binding data. `result` will be passed to JSON.stringify unless it is - * a string, Buffer, ArrayBufferView, or number. - * - * @deprecated Use of sync functions with `context.done()` is not recommended. Use async/await and pass the response as the return value instead. - * See the docs here for more information: https://aka.ms/functions-js-async-await - */ - done(err?: Error | string | null, result?: any): void; - /** - * HTTP request object. Provided to your function when using HTTP Bindings. - */ - req?: HttpRequest; - /** - * HTTP response object. Provided to your function when using HTTP Bindings. - */ - res?: { - [key: string]: any; - }; - } - /** - * HTTP request headers. - */ - export interface HttpRequestHeaders { - [name: string]: string; - } - /** - * HTTP response headers. - */ - export interface HttpResponseHeaders { - [name: string]: string; - } - /** - * Query string parameter keys and values from the URL. - */ - export interface HttpRequestQuery { - [name: string]: string; - } - /** - * Route parameter keys and values. - */ - export interface HttpRequestParams { - [name: string]: string; - } - /** - * Object representing logged-in user, either through - * AppService/Functions authentication, or SWA Authentication - */ - export interface HttpRequestUser { - /** - * Type of authentication, either AppService or StaticWebApps - */ - type: HttpRequestUserType; - /** - * unique user GUID - */ - id: string; - /** - * unique username - */ - username: string; - /** - * provider of authentication service - */ - identityProvider: string; - /** - * Extra authentication information, dependent on auth type - * and auth provider - */ - claimsPrincipalData: { - [key: string]: any; - }; - } - /** - * HTTP request object. Provided to your function when using HTTP Bindings. - */ - export interface HttpRequest { - /** - * HTTP request method used to invoke this function. - */ - method: HttpMethod | null; - /** - * Request URL. - */ - url: string; - /** - * HTTP request headers. - */ - headers: HttpRequestHeaders; - /** - * Query string parameter keys and values from the URL. - */ - query: HttpRequestQuery; - /** - * Route parameter keys and values. - */ - params: HttpRequestParams; - /** - * Object representing logged-in user, either through - * AppService/Functions authentication, or SWA Authentication - * null when no such user is logged in. - */ - user: HttpRequestUser | null; - /** - * The HTTP request body. - */ - body?: any; - /** - * The HTTP request body as a UTF-8 string. - */ - rawBody?: any; - - /** - * Parses the body and returns an object representing a form - * @throws if the content type is not "multipart/form-data" or "application/x-www-form-urlencoded" - */ - parseFormBody(): Form; - } - - export interface Form extends Iterable<[string, FormPart]> { - /** - * Returns the value of the first name-value pair whose name is `name`. If there are no such pairs, `null` is returned. - */ - get(name: string): FormPart | null; - - /** - * Returns the values of all name-value pairs whose name is `name`. If there are no such pairs, an empty array is returned. - */ - getAll(name: string): FormPart[]; - - /** - * Returns `true` if there is at least one name-value pair whose name is `name`. - */ - has(name: string): boolean; - - /** - * The number of parts in this form - */ - length: number; - } - - export interface FormPart { - /** - * The value for this part of the form - */ - value: Buffer; - - /** - * The file name for this part of the form, if specified - */ - fileName?: string; - - /** - * The content type for this part of the form, assumed to be "text/plain" if not specified - */ - contentType?: string; - } - - /** - * Possible values for an HTTP request method. - */ - export type HttpMethod = 'GET' | 'POST' | 'DELETE' | 'HEAD' | 'PATCH' | 'PUT' | 'OPTIONS' | 'TRACE' | 'CONNECT'; - /** - * Possible values for an HTTP Request user type - */ - export type HttpRequestUserType = 'AppService' | 'StaticWebApps'; - /** - * Http response object and methods. - * This is the default of the res property in the Context object provided to your function when using HTTP triggers. - */ - export interface HttpResponseFull { - /** - * HTTP response headers. - */ - headers?: HttpResponseHeaders; - /** - * HTTP response cookies. - */ - cookies?: Cookie[]; - /** - * HTTP response body. - */ - body?: any; - /** - * HTTP response status code. - * @default 200 - */ - statusCode?: number | string; - /** - * Enable content negotiation of response body if true - * If false, treat response body as raw - * @default false - */ - enableContentNegotiation?: boolean; - /** - * Sets the HTTP response status code - * @returns the updated HttpResponseFull instance - */ - status: (statusCode: number | string) => HttpResponseFull; - /** - * Sets a particular header field to a value - * @returns the updated HttpResponseFull instance - */ - setHeader(field: string, val: any): HttpResponseFull; - /** - * Has the same functionality as setHeader. - * Sets a particular header field to a value - * @returns the updated HttpResponseFull instance - */ - header(field: string, val: any): HttpResponseFull; - /** - * Has the same functionality as setHeader. - * Sets a particular header field to a value - * @returns the updated HttpResponseFull instance - */ - set(field: string, val: any): HttpResponseFull; - /** - * Get the value of a particular header field - */ - getHeader(field: string): any; - /** - * Has the same functionality as getHeader - * Get the value of a particular header field - */ - get(field: string): any; - /** - * Removes a particular header field - * @returns the updated HttpResponseFull instance - */ - removeHeader(field: string): HttpResponseFull; - /** - * Set the 'Content-Type' header to a particular value - * @returns the updated HttpResponseFull instance - */ - type(type: string): HttpResponseFull; - /** - * Automatically sets the content-type then calls context.done() - * @returns updated HttpResponseFull instance - * @deprecated this method calls context.done() which is deprecated, use async/await and pass the response as the return value instead. - * See the docs here for more information: https://aka.ms/functions-js-async-await - */ - send(body?: any): HttpResponseFull; - /** - * Same as send() - * Automatically sets the content-type then calls context.done() - * @returns updated HttpResponseFull instance - * @deprecated this method calls context.done() which is deprecated, use async/await and pass the response as your function's return value instead. - * See the docs here for more information: https://aka.ms/functions-js-async-await - */ - end(body?: any): HttpResponseFull; - /** - * Sets the status code then calls send() - * @returns updated HttpResponseFull instance - * @deprecated this method calls context.done() which is deprecated, use async/await and pass the response as your function's return value instead. - * See the docs here for more information: https://aka.ms/functions-js-async-await - */ - sendStatus(statusCode: string | number): HttpResponseFull; - /** - * Sets the 'Content-Type' header to 'application/json' then calls send(body) - * @deprecated this method calls context.done() which is deprecated, use async/await and pass the response as your function's return value instead. - * See the docs here for more information: https://aka.ms/functions-js-async-await - */ - json(body?: any): void; - } - /** - * Http response object. - * This is not the default on the Context object, but you may replace context.res with an object of this type when using HTTP triggers. - */ - export interface HttpResponseSimple { - /** - * HTTP response headers. - */ - headers?: HttpResponseHeaders; - /** - * HTTP response cookies. - */ - cookies?: Cookie[]; - /** - * HTTP response body. - */ - body?: any; - /** - * HTTP response status code. - * This property takes precedence over the `status` property - * @default 200 - */ - statusCode?: number | string; - /** - * HTTP response status code - * The same as `statusCode`. This property is ignored if `statusCode` is set - * @default 200 - */ - status?: number | string; - /** - * Enable content negotiation of response body if true - * If false, treat response body as raw - * @default false - */ - enableContentNegotiation?: boolean; - } - /** - * Http response type. - */ - export type HttpResponse = HttpResponseSimple | HttpResponseFull; - - /** - * Http response cookie object to "Set-Cookie" - */ - export interface Cookie { - /** Cookie name */ - name: string; - /** Cookie value */ - value: string; - /** Specifies allowed hosts to receive the cookie */ - domain?: string; - /** Specifies URL path that must exist in the requested URL */ - path?: string; - /** - * NOTE: It is generally recommended that you use maxAge over expires. - * Sets the cookie to expire at a specific date instead of when the client closes. - * This can be a Javascript Date or Unix time in milliseconds. - */ - expires?: Date | number; - /** Sets the cookie to only be sent with an encrypted request */ - secure?: boolean; - /** Sets the cookie to be inaccessible to JavaScript's Document.cookie API */ - httpOnly?: boolean; - /** Can restrict the cookie to not be sent with cross-site requests */ - sameSite?: 'Strict' | 'Lax' | 'None' | undefined; - /** Number of seconds until the cookie expires. A zero or negative number will expire the cookie immediately. */ - maxAge?: number; - } - export interface ExecutionContext { - /** - * A unique GUID per function invocation. - */ - invocationId: string; - /** - * The name of the function that is being invoked. The name of your function is always the same as the - * name of the corresponding function.json's parent directory. - */ - functionName: string; - /** - * The directory your function is in (this is the parent directory of this function's function.json). - */ - functionDirectory: string; - /** - * The retry context of the current function execution or null if the retry policy is not defined. - */ - retryContext: RetryContext | null; - } - export interface RetryContext { - /** - * Current retry count of the function executions. - */ - retryCount: number; - /** - * Max retry count is the maximum number of times an execution is retried before eventual failure. A value of -1 means to retry indefinitely. - */ - maxRetryCount: number; - /** - * Exception that caused the retry - */ - exception?: Exception; - } - export interface Exception { - /** Exception source */ - source?: string | null; - /** Exception stackTrace */ - stackTrace?: string | null; - /** Exception message */ - message?: string | null; - } - /** - * TraceContext information to enable distributed tracing scenarios. - */ - export interface TraceContext { - /** Describes the position of the incoming request in its trace graph in a portable, fixed-length format. */ - traceparent: string | null | undefined; - /** Extends traceparent with vendor-specific data. */ - tracestate: string | null | undefined; - /** Holds additional properties being sent as part of request telemetry. */ - attributes: - | { - [k: string]: string; - } - | null - | undefined; - } - export interface BindingDefinition { - /** - * The name of your binding, as defined in function.json. - */ - name: string; - /** - * The type of your binding, as defined in function.json. - */ - type: string; - /** - * The direction of your binding, as defined in function.json. - */ - direction: 'in' | 'out' | 'inout' | undefined; - } - /** - * Allows you to write streaming function logs. - */ - export interface Logger { - /** - * Writes streaming function logs at the default trace level. - */ - (...args: any[]): void; - /** - * Writes to error level logging or lower. - */ - error(...args: any[]): void; - /** - * Writes to warning level logging or lower. - */ - warn(...args: any[]): void; - /** - * Writes to info level logging or lower. - */ - info(...args: any[]): void; - /** - * Writes to verbose level logging. - */ - verbose(...args: any[]): void; - } - /** - * Timer schedule information. Provided to your function when using a timer binding. - */ - export interface Timer { - /** - * Whether this timer invocation is due to a missed schedule occurrence. - */ - isPastDue: boolean; - schedule: { - /** - * Whether intervals between invocations should account for DST. - */ - adjustForDST: boolean; - }; - scheduleStatus: { - /** - * The last recorded schedule occurrence. Date ISO string. - */ - last: string; - /** - * The expected next schedule occurrence. Date ISO string. - */ - next: string; - /** - * The last time this record was updated. This is used to re-calculate `next` with the current schedule after a host restart. Date ISO string. - */ - lastUpdated: string; - }; - } -} +import { Context } from './Context'; + +export * from './Context'; +export * from './http'; +export * from './timer'; + +/** + * Sets the programming model contained in this package to be the one used by the Azure Functions worker + */ +export declare function setup(): void; + +/** + * Interface for your Azure Function code. This function must be exported (via module.exports or exports) + * and will execute when triggered. It is recommended that you declare this function as async, which + * implicitly returns a Promise. + * @param context Context object passed to your function from the Azure Functions runtime. + * @param {any[]} args Optional array of input and trigger binding data. These binding data are passed to the + * function in the same order that they are defined in function.json. Valid input types are string, HttpRequest, + * and Buffer. + * @returns Output bindings (optional). If you are returning a result from a Promise (or an async function), this + * result will be passed to JSON.stringify unless it is a string, Buffer, ArrayBufferView, or number. + */ +export type AzureFunction = (context: Context, ...args: any[]) => Promise | void; diff --git a/types/timer.d.ts b/types/timer.d.ts new file mode 100644 index 0000000..ee375a0 --- /dev/null +++ b/types/timer.d.ts @@ -0,0 +1,32 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the MIT License. + +/** + * Timer schedule information. Provided to your function when using a timer binding. + */ +export interface Timer { + /** + * Whether this timer invocation is due to a missed schedule occurrence. + */ + isPastDue: boolean; + schedule: { + /** + * Whether intervals between invocations should account for DST. + */ + adjustForDST: boolean; + }; + scheduleStatus: { + /** + * The last recorded schedule occurrence. Date ISO string. + */ + last: string; + /** + * The expected next schedule occurrence. Date ISO string. + */ + next: string; + /** + * The last time this record was updated. This is used to re-calculate `next` with the current schedule after a host restart. Date ISO string. + */ + lastUpdated: string; + }; +} diff --git a/types/tsconfig.json b/types/tsconfig.json deleted file mode 100644 index 34d4f72..0000000 --- a/types/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es6", - "strict": true, - "outDir": "dist" - } -} \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index 3998fbb..c28d6cb 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,23 +1,45 @@ -module.exports = { - entry: "./dist/src/index.js", - output: { - path: `${__dirname}/dist/src`, - filename: "index-bundle.js", - libraryTarget: "commonjs2" - }, - target: 'node', - node: { - __dirname: false - }, - externals: { - '@azure/functions-core': 'commonjs2 @azure/functions-core' - }, - module: { - parser: { - javascript: { - commonjsMagicComments: true - } - } - }, - plugins: [] -}; \ No newline at end of file +const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); +const ESLintPlugin = require('eslint-webpack-plugin'); + +module.exports = (_env, argv) => { + const isDevMode = argv.mode === "development"; + return { + entry: "./src/index.ts", + target: 'node', + node: { + __dirname: false + }, + devtool: 'source-map', + externals: [ + /^[^\.]+/ + ], + module: { + parser: { + javascript: { + commonjsMagicComments: true + }, + }, + rules: [ + { + test: /\.tsx?$/, + loader: 'ts-loader' + } + ] + }, + resolve: { + extensions: ['.ts', '.tsx', '.js'] + }, + output: { + path: `${__dirname}/dist/`, + filename: isDevMode ? "azure-functions.js" : "azure-functions.min.js", + libraryTarget: "commonjs2" + }, + plugins: [ + new ForkTsCheckerWebpackPlugin({}), + new ESLintPlugin({ + files: ['src/**/*.ts', 'test/**/*.ts'], + fix: isDevMode + }) + ] + }; +}