Browse Source

更新页面布局

嘀嘀嘀 2 years ago
parent
commit
d96fe04fef
100 changed files with 68904 additions and 2 deletions
  1. 0 1
      README.md
  2. 16 0
      node_modules/.bin/mime
  3. 17 0
      node_modules/.bin/mime.cmd
  4. 28 0
      node_modules/.bin/mime.ps1
  5. 37 1
      node_modules/.package-lock.json
  6. 459 0
      node_modules/@xmldom/xmldom/CHANGELOG.md
  7. 8 0
      node_modules/@xmldom/xmldom/LICENSE
  8. 50 0
      node_modules/@xmldom/xmldom/SECURITY.md
  9. 43 0
      node_modules/@xmldom/xmldom/index.d.ts
  10. 2 0
      node_modules/@xmldom/xmldom/lib/.eslintrc.yml
  11. 203 0
      node_modules/@xmldom/xmldom/lib/conventions.js
  12. 322 0
      node_modules/@xmldom/xmldom/lib/dom-parser.js
  13. 1840 0
      node_modules/@xmldom/xmldom/lib/dom.js
  14. 2166 0
      node_modules/@xmldom/xmldom/lib/entities.js
  15. 4 0
      node_modules/@xmldom/xmldom/lib/index.js
  16. 662 0
      node_modules/@xmldom/xmldom/lib/sax.js
  17. 71 0
      node_modules/@xmldom/xmldom/package.json
  18. 356 0
      node_modules/@xmldom/xmldom/readme.md
  19. 55 0
      node_modules/cos-js-sdk-v5/.github/workflows/auto-changelog.yml
  20. 10 0
      node_modules/cos-js-sdk-v5/.prettierrc
  21. 1262 0
      node_modules/cos-js-sdk-v5/CHANGELOG.md
  22. 21 0
      node_modules/cos-js-sdk-v5/LICENSE
  23. 121 0
      node_modules/cos-js-sdk-v5/README.md
  24. 15 0
      node_modules/cos-js-sdk-v5/babel.config.js
  25. 17 0
      node_modules/cos-js-sdk-v5/bower.json
  26. 79 0
      node_modules/cos-js-sdk-v5/csp/AllowAction.md
  27. 7 0
      node_modules/cos-js-sdk-v5/csp/README.md
  28. 1936 0
      node_modules/cos-js-sdk-v5/csp/api.md
  29. 156 0
      node_modules/cos-js-sdk-v5/csp/auth-json.php
  30. 651 0
      node_modules/cos-js-sdk-v5/csp/csp.html
  31. 80 0
      node_modules/cos-js-sdk-v5/csp/start.md
  32. 1603 0
      node_modules/cos-js-sdk-v5/csp/test.html
  33. 1693 0
      node_modules/cos-js-sdk-v5/demo/CIDemos/ai.js
  34. 980 0
      node_modules/cos-js-sdk-v5/demo/CIDemos/asr.js
  35. 588 0
      node_modules/cos-js-sdk-v5/demo/CIDemos/audit.js
  36. 197 0
      node_modules/cos-js-sdk-v5/demo/CIDemos/common.js
  37. 307 0
      node_modules/cos-js-sdk-v5/demo/CIDemos/docPreview.js
  38. 419 0
      node_modules/cos-js-sdk-v5/demo/CIDemos/fileProcess.js
  39. 122 0
      node_modules/cos-js-sdk-v5/demo/CIDemos/index.js
  40. 1135 0
      node_modules/cos-js-sdk-v5/demo/CIDemos/mediaProcess.js
  41. 571 0
      node_modules/cos-js-sdk-v5/demo/CIDemos/picProcess.js
  42. 1012 0
      node_modules/cos-js-sdk-v5/demo/CIDemos/taskAndWorkflow.js
  43. 40 0
      node_modules/cos-js-sdk-v5/demo/common/async.js
  44. 219 0
      node_modules/cos-js-sdk-v5/demo/common/cos-auth.js
  45. 1 0
      node_modules/cos-js-sdk-v5/demo/common/cos-auth.min.js
  46. 2 0
      node_modules/cos-js-sdk-v5/demo/common/jquery-3.3.1.min.js
  47. 29 0
      node_modules/cos-js-sdk-v5/demo/common/lodash.core.min.js
  48. 6 0
      node_modules/cos-js-sdk-v5/demo/common/vue.min.js
  49. BIN
      node_modules/cos-js-sdk-v5/demo/cors.png
  50. 53 0
      node_modules/cos-js-sdk-v5/demo/crc64.html
  51. 17990 0
      node_modules/cos-js-sdk-v5/demo/crc64.js
  52. 1822 0
      node_modules/cos-js-sdk-v5/demo/demo.js
  53. 1 0
      node_modules/cos-js-sdk-v5/demo/empty.html
  54. 19 0
      node_modules/cos-js-sdk-v5/demo/folder/index.html
  55. 332 0
      node_modules/cos-js-sdk-v5/demo/index.html
  56. 101 0
      node_modules/cos-js-sdk-v5/demo/mime-limit.html
  57. 1 0
      node_modules/cos-js-sdk-v5/demo/noSDK/empty.html
  58. 191 0
      node_modules/cos-js-sdk-v5/demo/noSDK/form_sign.html
  59. 193 0
      node_modules/cos-js-sdk-v5/demo/noSDK/form_sts.html
  60. 158 0
      node_modules/cos-js-sdk-v5/demo/noSDK/post_sign.html
  61. 158 0
      node_modules/cos-js-sdk-v5/demo/noSDK/post_sts.html
  62. 138 0
      node_modules/cos-js-sdk-v5/demo/noSDK/put_sign.html
  63. 144 0
      node_modules/cos-js-sdk-v5/demo/noSDK/put_sts.html
  64. 144 0
      node_modules/cos-js-sdk-v5/demo/policy-form.html
  65. 137 0
      node_modules/cos-js-sdk-v5/demo/policy-post.html
  66. 193 0
      node_modules/cos-js-sdk-v5/demo/post_sign.html
  67. 66 0
      node_modules/cos-js-sdk-v5/demo/queue/index.html
  68. 77 0
      node_modules/cos-js-sdk-v5/demo/queue/index.js
  69. 78 0
      node_modules/cos-js-sdk-v5/demo/queue/style.css
  70. 170 0
      node_modules/cos-js-sdk-v5/demo/slice-task.html
  71. 129 0
      node_modules/cos-js-sdk-v5/demo/slice.html
  72. 134 0
      node_modules/cos-js-sdk-v5/demo/sts-form.html
  73. 126 0
      node_modules/cos-js-sdk-v5/demo/sts-post.html
  74. 129 0
      node_modules/cos-js-sdk-v5/demo/sts-put-server-key.html
  75. 128 0
      node_modules/cos-js-sdk-v5/demo/sts-put.html
  76. 56 0
      node_modules/cos-js-sdk-v5/demo/vueDemo/index.html
  77. 185 0
      node_modules/cos-js-sdk-v5/demo/vueDemo/index.js
  78. 6 0
      node_modules/cos-js-sdk-v5/demo/vueDemo/vue.min.js
  79. 15644 0
      node_modules/cos-js-sdk-v5/dist/cos-js-sdk-v5.js
  80. 1 0
      node_modules/cos-js-sdk-v5/dist/cos-js-sdk-v5.min.js
  81. 2581 0
      node_modules/cos-js-sdk-v5/index.d.ts
  82. 2 0
      node_modules/cos-js-sdk-v5/index.js
  83. 12 0
      node_modules/cos-js-sdk-v5/jest.config.js
  84. 170 0
      node_modules/cos-js-sdk-v5/lib/base64.js
  85. 1 0
      node_modules/cos-js-sdk-v5/lib/beacon.min.js
  86. 128 0
      node_modules/cos-js-sdk-v5/lib/crypto.js
  87. 167 0
      node_modules/cos-js-sdk-v5/lib/json2xml.js
  88. 618 0
      node_modules/cos-js-sdk-v5/lib/md5.js
  89. 139 0
      node_modules/cos-js-sdk-v5/lib/request.js
  90. 166 0
      node_modules/cos-js-sdk-v5/lib/xml2json.js
  91. 47 0
      node_modules/cos-js-sdk-v5/package.json
  92. 171 0
      node_modules/cos-js-sdk-v5/server/qcloud-sts-sdk.php
  93. 480 0
      node_modules/cos-js-sdk-v5/server/sts.js
  94. 41 0
      node_modules/cos-js-sdk-v5/server/sts.php
  95. 1455 0
      node_modules/cos-js-sdk-v5/src/advance.js
  96. 59 0
      node_modules/cos-js-sdk-v5/src/async.js
  97. 4216 0
      node_modules/cos-js-sdk-v5/src/base.js
  98. 95 0
      node_modules/cos-js-sdk-v5/src/cos.js
  99. 34 0
      node_modules/cos-js-sdk-v5/src/event.js
  100. 0 0
      node_modules/cos-js-sdk-v5/src/session.js

+ 0 - 1
README.md

@@ -1 +0,0 @@
-#minsu_goodsmonent_manage

+ 16 - 0
node_modules/.bin/mime

@@ -0,0 +1,16 @@
+#!/bin/sh
+basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
+
+case `uname` in
+    *CYGWIN*|*MINGW*|*MSYS*)
+        if command -v cygpath > /dev/null 2>&1; then
+            basedir=`cygpath -w "$basedir"`
+        fi
+    ;;
+esac
+
+if [ -x "$basedir/node" ]; then
+  exec "$basedir/node"  "$basedir/../mime/cli.js" "$@"
+else 
+  exec node  "$basedir/../mime/cli.js" "$@"
+fi

+ 17 - 0
node_modules/.bin/mime.cmd

@@ -0,0 +1,17 @@
+@ECHO off
+GOTO start
+:find_dp0
+SET dp0=%~dp0
+EXIT /b
+:start
+SETLOCAL
+CALL :find_dp0
+
+IF EXIST "%dp0%\node.exe" (
+  SET "_prog=%dp0%\node.exe"
+) ELSE (
+  SET "_prog=node"
+  SET PATHEXT=%PATHEXT:;.JS;=;%
+)
+
+endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%"  "%dp0%\..\mime\cli.js" %*

+ 28 - 0
node_modules/.bin/mime.ps1

@@ -0,0 +1,28 @@
+#!/usr/bin/env pwsh
+$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
+
+$exe=""
+if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
+  # Fix case when both the Windows and Linux builds of Node
+  # are installed in the same directory
+  $exe=".exe"
+}
+$ret=0
+if (Test-Path "$basedir/node$exe") {
+  # Support pipeline input
+  if ($MyInvocation.ExpectingInput) {
+    $input | & "$basedir/node$exe"  "$basedir/../mime/cli.js" $args
+  } else {
+    & "$basedir/node$exe"  "$basedir/../mime/cli.js" $args
+  }
+  $ret=$LASTEXITCODE
+} else {
+  # Support pipeline input
+  if ($MyInvocation.ExpectingInput) {
+    $input | & "node$exe"  "$basedir/../mime/cli.js" $args
+  } else {
+    & "node$exe"  "$basedir/../mime/cli.js" $args
+  }
+  $ret=$LASTEXITCODE
+}
+exit $ret

+ 37 - 1
node_modules/.package-lock.json

@@ -1,7 +1,7 @@
 {
 {
     "name": "Usecloud.uniCloud.admin.usemall",
     "name": "Usecloud.uniCloud.admin.usemall",
     "version": "1.0.9",
     "version": "1.0.9",
-    "lockfileVersion": 2,
+    "lockfileVersion": 3,
     "requires": true,
     "requires": true,
     "packages": {
     "packages": {
         "node_modules/@babel/parser": {
         "node_modules/@babel/parser": {
@@ -25,6 +25,14 @@
                 "source-map": "^0.6.1"
                 "source-map": "^0.6.1"
             }
             }
         },
         },
+        "node_modules/@xmldom/xmldom": {
+            "version": "0.8.10",
+            "resolved": "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
+            "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
+            "engines": {
+                "node": ">=10.0.0"
+            }
+        },
         "node_modules/async-validator": {
         "node_modules/async-validator": {
             "version": "1.8.5",
             "version": "1.8.5",
             "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-1.8.5.tgz",
             "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-1.8.5.tgz",
@@ -62,6 +70,23 @@
             "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.",
             "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.",
             "hasInstallScript": true
             "hasInstallScript": true
         },
         },
+        "node_modules/cos-js-sdk-v5": {
+            "version": "1.5.0",
+            "resolved": "https://registry.npmmirror.com/cos-js-sdk-v5/-/cos-js-sdk-v5-1.5.0.tgz",
+            "integrity": "sha512-1Y3VFFIaPnnCcxJRoWRrCCxmhihihMjDh+2F61iUdT6fOGtVq8hYPQF6uBnKNwB/aF41wCeBgvibGy0wimXDlA==",
+            "dependencies": {
+                "@xmldom/xmldom": "^0.8.6"
+            }
+        },
+        "node_modules/cos-wx-sdk-v5": {
+            "version": "1.4.13",
+            "resolved": "https://registry.npmmirror.com/cos-wx-sdk-v5/-/cos-wx-sdk-v5-1.4.13.tgz",
+            "integrity": "sha512-cTrccf+9sfihCiRnj1BcHeYsQu7T6tXMrFVK2hnHPr/uJHv6Qui7hFHQyjngx0mJPsQEaq0jn7QmrwWL9nWwsA==",
+            "dependencies": {
+                "@xmldom/xmldom": "^0.8.6",
+                "mime": "^2.4.6"
+            }
+        },
         "node_modules/countup.js": {
         "node_modules/countup.js": {
             "version": "1.9.3",
             "version": "1.9.3",
             "resolved": "https://registry.npmmirror.com/countup.js/-/countup.js-1.9.3.tgz",
             "resolved": "https://registry.npmmirror.com/countup.js/-/countup.js-1.9.3.tgz",
@@ -134,6 +159,17 @@
                 }
                 }
             }
             }
         },
         },
+        "node_modules/mime": {
+            "version": "2.6.0",
+            "resolved": "https://registry.npmmirror.com/mime/-/mime-2.6.0.tgz",
+            "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==",
+            "bin": {
+                "mime": "cli.js"
+            },
+            "engines": {
+                "node": ">=4.0.0"
+            }
+        },
         "node_modules/nanoid": {
         "node_modules/nanoid": {
             "version": "3.3.6",
             "version": "3.3.6",
             "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.6.tgz",
             "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.6.tgz",

+ 459 - 0
node_modules/@xmldom/xmldom/CHANGELOG.md

@@ -0,0 +1,459 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [0.8.10](https://github.com/xmldom/xmldom/compare/0.8.9...0.8.10)
+
+### Fixed
+
+- dom: prevent iteration over deleted items [`#514`](https://github.com/xmldom/xmldom/pull/514)/ [`#499`](https://github.com/xmldom/xmldom/issues/499)
+
+Thank you, [@qtow](https://github.com/qtow), for your contributions
+
+
+## [0.8.9](https://github.com/xmldom/xmldom/compare/0.8.8...0.8.9)
+
+### Fixed
+
+- Set nodeName property in ProcessingInstruction [`#509`](https://github.com/xmldom/xmldom/pull/509) / [`#505`](https://github.com/xmldom/xmldom/issues/505)
+
+Thank you, [@cjbarth](https://github.com/cjbarth), for your contributions
+
+
+## [0.8.8](https://github.com/xmldom/xmldom/compare/0.8.7...0.8.8)
+
+### Fixed
+
+- extend list of HTML entities [`#489`](https://github.com/xmldom/xmldom/pull/489)
+
+Thank you, [@zorkow](https://github.com/zorkow), for your contributions
+
+## [0.8.7](https://github.com/xmldom/xmldom/compare/0.8.6...0.8.7)
+
+### Fixed
+
+- properly parse closing where the last attribute has no value [`#485`](https://github.com/xmldom/xmldom/pull/485) / [`#486`](https://github.com/xmldom/xmldom/issues/486)
+
+Thank you, [@bulandent](https://github.com/bulandent), for your contributions
+
+
+## [0.7.10](https://github.com/xmldom/xmldom/compare/0.7.9...0.7.10)
+
+### Fixed
+
+- properly parse closing where the last attribute has no value [`#485`](https://github.com/xmldom/xmldom/pull/485) / [`#486`](https://github.com/xmldom/xmldom/issues/486)
+
+Thank you, [@bulandent](https://github.com/bulandent), for your contributions
+
+
+## [0.8.6](https://github.com/xmldom/xmldom/compare/0.8.5...0.8.6)
+
+### Fixed
+
+- Properly check nodes before replacement [`#457`](https://github.com/xmldom/xmldom/pull/457) / [`#455`](https://github.com/xmldom/xmldom/issues/455) / [`#456`](https://github.com/xmldom/xmldom/issues/456)
+
+Thank you, [@edemaine](https://github.com/edemaine), [@pedro-l9](https://github.com/pedro-l9), for your contributions
+
+
+## [0.8.5](https://github.com/xmldom/xmldom/compare/0.8.4...0.8.5)
+
+### Fixed
+
+- fix: Restore ES5 compatibility [`#452`](https://github.com/xmldom/xmldom/pull/452) / [`#453`](https://github.com/xmldom/xmldom/issues/453)
+
+Thank you, [@fengxinming](https://github.com/fengxinming), for your contributions
+
+
+## [0.8.4](https://github.com/xmldom/xmldom/compare/0.8.3...0.8.4)
+
+### Fixed
+
+- Security: Prevent inserting DOM nodes when they are not well-formed [`CVE-2022-39353`](https://github.com/xmldom/xmldom/security/advisories/GHSA-crh6-fp67-6883)
+  In case such a DOM would be created, the part that is not well-formed will be transformed into text nodes, in which xml specific characters like `<` and `>` are encoded accordingly.
+  In the upcoming version 0.9.0 those text nodes will no longer be added and an error will be thrown instead.
+  This change can break your code, if you relied on this behavior, e.g. multiple root elements in the past. We consider it more important to align with the specs that we want to be aligned with, considering the potential security issues that might derive from people not being aware of the difference in behavior.
+  Related Spec: <https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity>
+
+Thank you, [@frumioj](https://github.com/frumioj), [@cjbarth](https://github.com/cjbarth), [@markgollnick](https://github.com/markgollnick) for your contributions
+
+
+## [0.8.3](https://github.com/xmldom/xmldom/compare/0.8.3...0.8.2)
+
+### Fixed
+- Avoid iterating over prototype properties [`#437`](https://github.com/xmldom/xmldom/pull/437) / [`#436`](https://github.com/xmldom/xmldom/issues/436)
+
+Thank you, [@Supraja9726](https://github.com/Supraja9726) for your contributions
+
+
+## [0.8.2](https://github.com/xmldom/xmldom/compare/0.8.1...0.8.2)
+
+### Fixed
+- fix(dom): Serialize `&gt;` as specified (#395) [`#58`](https://github.com/xmldom/xmldom/issues/58)
+
+### Other
+- docs: Add `nodeType` values to public interface description [`#396`](https://github.com/xmldom/xmldom/pull/396)
+- test: Add executable examples for node and typescript [`#317`](https://github.com/xmldom/xmldom/pull/317)
+- fix(dom): Serialize `&gt;` as specified [`#395`](https://github.com/xmldom/xmldom/pull/395)
+- chore: Add minimal `Object.assign` ponyfill [`#379`](https://github.com/xmldom/xmldom/pull/379)
+- docs: Refine release documentation [`#378`](https://github.com/xmldom/xmldom/pull/378)
+- chore: update various dev dependencies
+
+Thank you [@niklasl](https://github.com/niklasl), [@cburatto](https://github.com/cburatto), [@SheetJSDev](https://github.com/SheetJSDev), [@pyrsmk](https://github.com/pyrsmk) for your contributions
+
+## [0.8.1](https://github.com/xmldom/xmldom/compare/0.8.0...0.8.1)
+
+### Fixes
+- Only use own properties in entityMap [`#374`](https://github.com/xmldom/xmldom/pull/374)
+
+### Docs
+- Add security policy [`#365`](https://github.com/xmldom/xmldom/pull/365)
+- changelog: Correct contributor name and link [`#366`](https://github.com/xmldom/xmldom/pull/366)
+- Describe release/publish steps [`#358`](https://github.com/xmldom/xmldom/pull/358), [`#376`](https://github.com/xmldom/xmldom/pull/376)
+- Add snyk package health badge [`#360`](https://github.com/xmldom/xmldom/pull/360)
+
+
+## [0.8.0](https://github.com/xmldom/xmldom/compare/0.7.5...0.8.0)
+
+### Fixed
+- Normalize all line endings according to XML specs [1.0](https://w3.org/TR/xml/#sec-line-ends) and [1.1](https://www.w3.org/TR/xml11/#sec-line-ends) \
+  BREAKING CHANGE: Certain combination of line break characters are normalized to a single `\n` before parsing takes place and will no longer be preserved.
+  - [`#303`](https://github.com/xmldom/xmldom/issues/303) / [`#307`](https://github.com/xmldom/xmldom/pull/307)
+  - [`#49`](https://github.com/xmldom/xmldom/issues/49), [`#97`](https://github.com/xmldom/xmldom/issues/97), [`#324`](https://github.com/xmldom/xmldom/issues/324) / [`#314`](https://github.com/xmldom/xmldom/pull/314)
+- XMLSerializer: Preserve whitespace character references [`#284`](https://github.com/xmldom/xmldom/issues/284) / [`#310`](https://github.com/xmldom/xmldom/pull/310) \
+  BREAKING CHANGE: If you relied on the not spec compliant preservation of literal `\t`, `\n` or `\r` in **attribute values**.
+  To preserve those you will have to create XML that instead contains the correct numerical (or hexadecimal) equivalent (e.g. `&#x9;`, `&#xA;`, `&#xD;`).
+- Drop deprecated exports `DOMImplementation` and `XMLSerializer` from `lib/dom-parser.js` [#53](https://github.com/xmldom/xmldom/issues/53) / [`#309`](https://github.com/xmldom/xmldom/pull/309)
+  BREAKING CHANGE: Use the one provided by the main package export.
+- dom: Remove all links as part of `removeChild` [`#343`](https://github.com/xmldom/xmldom/issues/343) / [`#355`](https://github.com/xmldom/xmldom/pull/355)
+
+### Chore
+- ci: Restore latest tested node version to 16.x [`#325`](https://github.com/xmldom/xmldom/pull/325)
+- ci: Split test and lint steps into jobs [`#111`](https://github.com/xmldom/xmldom/issues/111) / [`#304`](https://github.com/xmldom/xmldom/pull/304)
+- Pinned and updated devDependencies
+
+Thank you [@marrus-sh](https://github.com/marrus-sh), [@victorandree](https://github.com/victorandree), [@mdierolf](https://github.com/mdierolf), [@tsabbay](https://github.com/tsabbay), [@fatihpense](https://github.com/fatihpense) for your contributions
+
+## 0.7.5
+
+[Commits](https://github.com/xmldom/xmldom/compare/0.7.4...0.7.5)
+
+### Fixes:
+
+- Preserve default namespace when serializing [`#319`](https://github.com/xmldom/xmldom/issues/319) / [`#321`](https://github.com/xmldom/xmldom/pull/321)
+  Thank you, [@lupestro](https://github.com/lupestro)
+
+## 0.7.4
+
+[Commits](https://github.com/xmldom/xmldom/compare/0.7.3...0.7.4)
+
+### Fixes:
+
+- Restore ability to parse `__prototype__` attributes [`#315`](https://github.com/xmldom/xmldom/pull/315)
+  Thank you, [@dsimpsonOMF](https://github.com/dsimpsonOMF)
+
+## 0.7.3
+
+[Commits](https://github.com/xmldom/xmldom/compare/0.7.2...0.7.3)
+
+### Fixes:
+
+- Add doctype when parsing from string [`#277`](https://github.com/xmldom/xmldom/issues/277) / [`#301`](https://github.com/xmldom/xmldom/pull/301)
+- Correct typo in error message [`#294`](https://github.com/xmldom/xmldom/pull/294)
+  Thank you, [@rrthomas](https://github.com/rrthomas)
+
+### Refactor:
+
+- Improve exports & require statements, new main package entry [`#233`](https://github.com/xmldom/xmldom/pull/233)
+
+### Docs:
+
+- Fix Stryker badge [`#298`](https://github.com/xmldom/xmldom/pull/298)
+- Fix link to help-wanted issues [`#299`](https://github.com/xmldom/xmldom/pull/299)
+
+### Chore:
+
+- Execute stryker:dry-run on branches [`#302`](https://github.com/xmldom/xmldom/pull/302)
+- Fix stryker config [`#300`](https://github.com/xmldom/xmldom/pull/300)
+- Split test and lint scripts [`#297`](https://github.com/xmldom/xmldom/pull/297)
+- Switch to stryker dashboard owned by org [`#292`](https://github.com/xmldom/xmldom/pull/292)
+
+## 0.7.2
+
+[Commits](https://github.com/xmldom/xmldom/compare/0.7.1...0.7.2)
+
+### Fixes:
+
+- Types: Add index.d.ts to packaged files [`#288`](https://github.com/xmldom/xmldom/pull/288)
+  Thank you, [@forty](https://github.com/forty)
+
+## 0.7.1
+
+[Commits](https://github.com/xmldom/xmldom/compare/0.7.0...0.7.1)
+
+### Fixes:
+
+- Types: Copy types from DefinitelyTyped [`#283`](https://github.com/xmldom/xmldom/pull/283)
+  Thank you, [@kachkaev](https://github.com/kachkaev)
+
+### Chore:
+- package.json: remove author, maintainers, etc. [`#279`](https://github.com/xmldom/xmldom/pull/279)
+
+## 0.7.0 
+
+[Commits](https://github.com/xmldom/xmldom/compare/0.6.0...0.7.0)
+
+Due to [`#271`](https://github.com/xmldom/xmldom/issue/271) this version was published as
+- unscoped `xmldom` package to github (git tags [`0.7.0`](https://github.com/xmldom/xmldom/tree/0.7.0) and [`0.7.0+unscoped`](https://github.com/xmldom/xmldom/tree/0.7.0%2Bunscoped))
+- scoped `@xmldom/xmldom` package to npm (git tag `0.7.0+scoped`)
+For more details look at [`#278`](https://github.com/xmldom/xmldom/pull/278#issuecomment-902172483)
+
+### Fixes:
+
+- Security: Misinterpretation of malicious XML input [`CVE-2021-32796`](https://github.com/xmldom/xmldom/security/advisories/GHSA-5fg8-2547-mr8q)
+- Implement `Document.getElementsByClassName` as specified [`#213`](https://github.com/xmldom/xmldom/pull/213), thank you, [@ChALkeR](https://github.com/ChALkeR)
+- Inherit namespace prefix from parent when required [`#268`](https://github.com/xmldom/xmldom/pull/268)
+- Handle whitespace in closing tags [`#267`](https://github.com/xmldom/xmldom/pull/267)
+- Update `DOMImplementation` according to recent specs [`#210`](https://github.com/xmldom/xmldom/pull/210)  
+  BREAKING CHANGE: Only if you "passed features to be marked as available as a constructor arguments" and expected it to "magically work".
+- No longer serializes any namespaces with an empty URI [`#244`](https://github.com/xmldom/xmldom/pull/244)   
+  (related to [`#168`](https://github.com/xmldom/xmldom/pull/168) released in 0.6.0)  
+  BREAKING CHANGE: Only if you rely on ["unsetting" a namespace prefix](https://github.com/xmldom/xmldom/pull/168#issuecomment-886984994) by setting it to an empty string 
+- Set `localName` as part of `Document.createElement` [`#229`](https://github.com/xmldom/xmldom/pull/229), thank you, [@rrthomas](https://github.com/rrthomas)
+
+### CI
+
+- We are now additionally running tests against node v16
+- Stryker tests on the master branch now run against node v14
+
+### Docs
+
+- Describe relations with and between specs: [`#211`](https://github.com/xmldom/xmldom/pull/211), [`#247`](https://github.com/xmldom/xmldom/pull/247)
+
+## 0.6.0
+
+[Commits](https://github.com/xmldom/xmldom/compare/0.5.0...0.6.0)
+
+### Fixes
+
+- Stop serializing empty namespace values like `xmlns:ds=""` [`#168`](https://github.com/xmldom/xmldom/pull/168)  
+  BREAKING CHANGE: If your code expected empty namespaces attributes to be serialized.  
+  Thank you, [@pdecat](https://github.com/pdecat) and [@FranckDepoortere](https://github.com/FranckDepoortere)
+- Escape `<` to `&lt;` when serializing attribute values [`#198`](https://github.com/xmldom/xmldom/issues/198) / [`#199`](https://github.com/xmldom/xmldom/pull/199)
+
+## 0.5.0
+
+[Commits](https://github.com/xmldom/xmldom/compare/0.4.0...0.5.0)
+
+### Fixes
+- Avoid misinterpretation of malicious XML input - [`GHSA-h6q6-9hqw-rwfv`](https://github.com/xmldom/xmldom/security/advisories/GHSA-h6q6-9hqw-rwfv) (CVE-2021-21366)
+  - Improve error reporting; throw on duplicate attribute\
+    BREAKING CHANGE: It is currently not clear how to consistently deal with duplicate attributes, so it's also safer for our users to fail when detecting them.
+    It's possible to configure the `DOMParser.errorHandler` before parsing, to handle those errors differently.
+
+    To accomplish this and also be able to verify it in tests I needed to
+    - create a new `Error` type `ParseError` and export it
+    - Throw `ParseError` from `errorHandler.fatalError` and prevent those from being caught in `XMLReader`.
+    - export `DOMHandler` constructor as `__DOMHandler`
+  - Preserve quotes in DOCTYPE declaration
+    Since the only purpose of parsing the DOCTYPE is to be able to restore it when serializing, we decided that it would be best to leave the parsed `publicId` and `systemId` as is, including any quotes.
+    BREAKING CHANGE: If somebody relies on the actual unquoted values of those ids, they will need to take care of either single or double quotes and the right escaping.
+    (Without this change this would not have been possible because the SAX parser already dropped the information about the quotes that have been used in the source.)
+
+    https://www.w3.org/TR/2006/REC-xml11-20060816/#dtd
+    https://www.w3.org/TR/2006/REC-xml11-20060816/#IDAX1KS (External Entity Declaration)
+
+- Fix breaking preprocessors' directives when parsing attributes [`#171`](https://github.com/xmldom/xmldom/pull/171)
+- fix(dom): Escape `]]&gt;` when serializing CharData [`#181`](https://github.com/xmldom/xmldom/pull/181)
+- Switch to (only) MIT license (drop problematic LGPL license option) [`#178`](https://github.com/xmldom/xmldom/pull/178)
+- Export DOMException; remove custom assertions; etc.  [`#174`](https://github.com/xmldom/xmldom/pull/174)
+
+### Docs
+- Update MDN links in `readme.md` [`#188`](https://github.com/xmldom/xmldom/pull/188)
+
+## 0.4.0
+
+[Commits](https://github.com/xmldom/xmldom/compare/0.3.0...0.4.0)
+
+### Fixes
+- **BREAKING** Restore `&nbsp;` behavior from v0.1.27 [`#67`](https://github.com/xmldom/xmldom/pull/67)
+- **BREAKING** Typecheck source param before parsing [`#113`](https://github.com/xmldom/xmldom/pull/113)
+- Include documents in package files list [`#156`](https://github.com/xmldom/xmldom/pull/156)
+- Preserve doctype with sysid [`#144`](https://github.com/xmldom/xmldom/pull/144)
+- Remove ES6 syntax from getElementsByClassName [`#91`](https://github.com/xmldom/xmldom/pull/91)
+- Revert "Add lowercase of åäö in entityMap" due to duplicate entries [`#84`](https://github.com/xmldom/xmldom/pull/84)
+- fix: Convert all line separators to LF [`#66`](https://github.com/xmldom/xmldom/pull/66)
+
+### Docs
+- Update CHANGELOG.md through version 0.3.0 [`#63`](https://github.com/xmldom/xmldom/pull/63)
+- Update badges [`#78`](https://github.com/xmldom/xmldom/pull/78)
+- Add .editorconfig file [`#104`](https://github.com/xmldom/xmldom/pull/104)
+- Add note about import [`#79`](https://github.com/xmldom/xmldom/pull/79)
+- Modernize & improve the example in readme.md [`#81`](https://github.com/xmldom/xmldom/pull/81)
+
+### CI
+- Add Stryker Mutator [`#70`](https://github.com/xmldom/xmldom/pull/70)
+- Add Stryker action to update dashboard [`#77`](https://github.com/xmldom/xmldom/pull/77)
+- Add Node GitHub action workflow [`#64`](https://github.com/xmldom/xmldom/pull/64)
+- add & enable eslint [`#106`](https://github.com/xmldom/xmldom/pull/106)
+- Use eslint-plugin-es5 to enforce ES5 syntax [`#107`](https://github.com/xmldom/xmldom/pull/107)
+- Recover `vows` tests, drop `proof` tests [`#59`](https://github.com/xmldom/xmldom/pull/59)
+- Add jest tessuite and first tests [`#114`](https://github.com/xmldom/xmldom/pull/114)
+- Add jest testsuite with `xmltest` cases [`#112`](https://github.com/xmldom/xmldom/pull/112)
+- Configure Renovate [`#108`](https://github.com/xmldom/xmldom/pull/108)
+- Test European HTML entities [`#86`](https://github.com/xmldom/xmldom/pull/86)
+- Updated devDependencies
+
+### Other
+- Remove files that are not of any use [`#131`](https://github.com/xmldom/xmldom/pull/131), [`#65`](https://github.com/xmldom/xmldom/pull/65), [`#33`](https://github.com/xmldom/xmldom/pull/33)
+
+## 0.3.0
+
+[Commits](https://github.com/xmldom/xmldom/compare/0.2.1...0.3.0)
+
+- **BREAKING** Node >=10.x is now required.
+- **BREAKING** Remove `component.json` (deprecated package manager https://github.com/componentjs/guide)
+- **BREAKING** Move existing sources into `lib` subdirectory.
+- **POSSIBLY BREAKING** Introduce `files` entry in `package.json` and remove use of `.npmignore`.
+- [Add `Document.getElementsByClassName`](https://github.com/xmldom/xmldom/issues/24).
+- [Add `Node` to the list of exports](https://github.com/xmldom/xmldom/pull/27)
+- [Add lowercase of åäö in `entityMap`](https://github.com/xmldom/xmldom/pull/23).
+- Move CHANGELOG to markdown file.
+- Move LICENSE to markdown file.
+
+## 0.2.1
+
+[Commits](https://github.com/xmldom/xmldom/compare/0.2.0...0.2.1)
+
+- Correct `homepage`, `repository` and `bugs` URLs in `package.json`.
+
+## 0.2.0
+
+[Commits](https://github.com/xmldom/xmldom/compare/v0.1.27...0.2.0)
+
+- Includes all **BREAKING** changes introduced in [`xmldom-alpha@v0.1.28`](#0128) by the original authors.
+- **POSSIBLY BREAKING** [remove the `Object.create` check from the `_extends` method of `dom.js` that added a `__proto__` property](https://github.com/xmldom/xmldom/commit/0be2ae910a8a22c9ec2cac042e04de4c04317d2a#diff-7d1c5d97786fdf9af5446a241d0b6d56L19-L22) ().
+- **POSSIBLY BREAKING** [remove code that added a `__proto__` property](https://github.com/xmldom/xmldom/commit/366159a76a181ce9a0d83f5dc48205686cfaf9cc)
+- formatting/corrections in `package.json`
+
+## 0.1.31
+
+[Commits](https://github.com/xmldom/xmldom/compare/v0.1.27...v0.1.31)
+
+The patch versions (`v0.1.29` - `v0.1.31`) that have been released on the [v0.1.x branch](https://github.com/xmldom/xmldom/tree/0.1.x), to reflect the changed maintainers, **are branched off from [`v0.1.27`](#0127) so they don't include the breaking changes introduced in [`xmldom-alpha@v0.1.28`](#0128)**:
+
+## Maintainer changes
+
+After the last commit to the original repository <https://github.com/jindw/xmldom> on the 9th of May 2017, the first commit to <https://github.com/xmldom/xmldom> is from the 19th of December 2019. [The fork has been announced in the original repository on the 2nd of March 2020.](https://github.com/jindw/xmldom/issues/259)
+
+The versions listed below have been published to one or both of the following packages:
+- <https://www.npmjs.com/package/xmldom-alpha>
+- <https://www.npmjs.com/package/xmldom>
+
+It is currently not planned to continue publishing the `xmldom-alpha` package.
+
+The new maintainers did not invest time to understand changes that led to the last `xmldom` version [`0.1.27`](#0127) published by the original maintainer, but consider it the basis for their work.
+A timeline of all the changes that happened from that version until `0.3.0` is available in <https://github.com/xmldom/xmldom/issues/62>. Any related questions should be asked there.
+
+## 0.1.28
+
+[Commits](https://github.com/xmldom/xmldom/compare/v0.1.27...xmldom-alpha@v0.1.28)
+
+Published by @jindw on the 9th of May 2017 as
+- `xmldom-alpha@0.1.28`
+
+- **BREAKING** includes [regression regarding `&nbsp;` (issue #57)](https://github.com/xmldom/xmldom/issues/57) 
+- [Fix `license` field in `package.json`](https://github.com/jindw/xmldom/pull/178)
+- [Conditional converting of HTML entities](https://github.com/jindw/xmldom/pull/80)
+- Fix `dom.js` serialization issue for missing document element ([example that failed on `toString()` before this change](https://github.com/xmldom/xmldom/blob/a58dcf7a265522e80ce520fe3be0cddb1b976f6f/test/parse/unclosedcomment.js#L10-L11))
+- Add new module `entities.js`
+
+## 0.1.27
+
+Published by @jindw on the 28th of Nov 2016 as 
+- `xmldom@0.1.27`
+- `xmldom-alpha@0.1.27` 
+
+- Various bug fixes.
+
+## 0.1.26
+
+Published on the 18th of Nov 2016
+as `xmldom@0.1.26`
+
+- Details unknown
+
+## 0.1.25
+
+Published on the 18th of Nov 2016 as 
+- `xmldom@0.1.25`
+
+- Details unknown
+
+## 0.1.24
+
+Published on the 27th of November 2016 as
+- `xmldom@0.1.24`
+- `xmldom-alpha@0.1.24`
+
+- Added node filter.
+
+## 0.1.23
+
+Published on the 5th of May 2016 as
+- `xmldom-alpha@0.1.23`
+
+- Add namespace support for nest node serialize.
+- Various other bug fixes.
+
+## 0.1.22
+
+- Merge XMLNS serialization.
+- Remove \r from source string.
+- Print namespaces for child elements.
+- Switch references to nodeType to use named constants.
+- Add nodelist toString support.
+
+## 0.1.21
+
+- Fix serialize bug.
+
+## 0.1.20
+
+- Optimize invalid XML support.
+- Add toString sorter for attributes output.
+- Add html self closed node button.
+- Add `*` NS support for getElementsByTagNameNS.
+- Convert attribute's value to string in setAttributeNS.
+- Add support for HTML entities for HTML docs only.
+- Fix TypeError when Document is created with DocumentType.
+
+## 0.1.19
+
+- Fix [infinite loop on unclosed comment (jindw/xmldom#68)](https://github.com/jindw/xmldom/issues/68)
+- Add error report for unclosed tag.
+- Various other fixes.
+
+## 0.1.18
+
+- Add default `ns` support.
+- parseFromString now renders entirely plain text documents as textNode.
+- Enable option to ignore white space on parsing.
+
+## 0.1.17
+
+**Details missing for this and potential earlier version**
+
+## 0.1.16
+
+- Correctly handle multibyte Unicode greater than two byts. #57. #56.
+- Initial unit testing and test coverage. #53. #46. #19.
+- Create Bower `component.json` #52.
+
+## 0.1.8
+
+- Add: some test case from node-o3-xml(excludes xpath support)
+- Fix: remove existed attribute before setting  (bug introduced in v0.1.5)
+- Fix: index direct access for childNodes and any NodeList collection(not w3c standard)
+- Fix: remove last child bug

+ 8 - 0
node_modules/@xmldom/xmldom/LICENSE

@@ -0,0 +1,8 @@
+Copyright 2019 - present Christopher J. Brody and other contributors, as listed in: https://github.com/xmldom/xmldom/graphs/contributors
+Copyright 2012 - 2017 @jindw <jindw@xidea.org> and other contributors, as listed in: https://github.com/jindw/xmldom/graphs/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.

+ 50 - 0
node_modules/@xmldom/xmldom/SECURITY.md

@@ -0,0 +1,50 @@
+# Security Policy
+
+The most up-to-date version of this document can be found at <https://github.com/xmldom/xmldom/security/policy>.
+
+## Supported Versions
+
+This repository contains the code for the libraries `xmldom` and `@xmldom/xmldom` on npm.
+
+As long as we didn't publish v1, we aim to maintain the last two minor versions with security fixes. If it is possible we provide security fixes as path versions.
+If you think there is a good reason to also patch an earlier version let us know in a github issue or the release discussion once the fix has been provided. 
+The maintainers will consider it and if we agree and have/find the required resources, a patch for that version will be provided.
+
+Please notice that [we are no longer able to publish the (unscoped) `xmldom` package](https://github.com/xmldom/xmldom/issues/271), 
+and that all existing versions of `xmldom` are affected by at least one security vulnerability and should be considered deprecated.
+You can still report issues regarding `xmldom` as described below.
+
+If you need help with migrating from `xmldom` to `@xmldom/xmldom`, file a github issue or PR in the affected repository and mention @karfau.
+
+## Reporting vulnerabilities
+
+Please email reports about any security related issues you find to `security@xmldom.org`, which will forward it to the list of maintainers. 
+The maintainers will try to respond within 7 calendar days. (If nobody peplies after 7 days, please us send a reminder!)
+As part of you communication please make sure to always hit "Reply all", so all maintainers are kept in the loop.
+
+In addition, please include the following information along with your report:
+
+- Your name and affiliation (if any).
+- A description of the technical details of the vulnerabilities. It is very important to let us know how we can reproduce your findings.
+- An explanation who can exploit this vulnerability, and what they gain when doing so -- write an attack scenario. This will help us evaluate your report quickly, especially if the issue is complex.
+- Whether this vulnerability public or known to third parties. If it is, please provide details.
+
+If you believe that an existing (public) issue is security-related, please send an email to `security@xmldom.org`. 
+The email should include the issue URL and a short description of why it should be handled according to this security policy.
+
+Once an issue is reported, the maintainers use the following disclosure process:
+
+- When a report is received, we confirm the issue, determine its severity and the affected versions.
+- If we know of specific third-party services or software based on xmldom that require mitigation before publication, those projects will be notified.
+- A [github security advisory](https://docs.github.com/en/code-security/security-advisories/about-github-security-advisories) is [created](https://docs.github.com/en/code-security/security-advisories/creating-a-security-advisory) (but not published) which details the problem and steps for mitigation.
+- If the reporter provides a github account and agrees to it, we (add that github account as a collaborator on the advisuory)[https://docs.github.com/en/code-security/security-advisories/adding-a-collaborator-to-a-security-advisory].
+- The vulnerability is fixed in a [private fork](https://docs.github.com/en/code-security/security-advisories/collaborating-in-a-temporary-private-fork-to-resolve-a-security-vulnerability) and potential workarounds are identified.
+- The maintainers audit the existing code to find any potential similar problems.
+- The release for the current minor version and the [security advisory are published](https://docs.github.com/en/code-security/security-advisories/publishing-a-security-advisory).
+- The release(s) for previous minor version(s) are published.
+
+We credit reporters for identifying security issues, if they confirm that they want to.
+
+## Known vulnerabilities
+
+See https://github.com/xmldom/xmldom/security/advisories?state=published

+ 43 - 0
node_modules/@xmldom/xmldom/index.d.ts

@@ -0,0 +1,43 @@
+/// <reference lib="dom" />
+
+declare module "@xmldom/xmldom" {
+  var DOMParser: DOMParserStatic;
+  var XMLSerializer: XMLSerializerStatic;
+  var DOMImplementation: DOMImplementationStatic;
+
+  interface DOMImplementationStatic {
+      new(): DOMImplementation;
+  }
+
+  interface DOMParserStatic {
+      new (): DOMParser;
+      new (options: Options): DOMParser;
+  }
+
+  interface XMLSerializerStatic {
+      new (): XMLSerializer;
+  }
+
+  interface DOMParser {
+      parseFromString(xmlsource: string, mimeType?: string): Document;
+  }
+
+  interface XMLSerializer {
+      serializeToString(node: Node): string;
+  }
+
+  interface Options {
+      locator?: any;
+      errorHandler?: ErrorHandlerFunction | ErrorHandlerObject | undefined;
+  }
+
+  interface ErrorHandlerFunction {
+      (level: string, msg: any): any;
+  }
+
+  interface ErrorHandlerObject {
+      warning?: ((msg: any) => any) | undefined;
+      error?: ((msg: any) => any) | undefined;
+      fatalError?: ((msg: any) => any) | undefined;
+  }
+}

+ 2 - 0
node_modules/@xmldom/xmldom/lib/.eslintrc.yml

@@ -0,0 +1,2 @@
+extends:
+  - 'plugin:es5/no-es2015'

+ 203 - 0
node_modules/@xmldom/xmldom/lib/conventions.js

@@ -0,0 +1,203 @@
+'use strict'
+
+/**
+ * Ponyfill for `Array.prototype.find` which is only available in ES6 runtimes.
+ *
+ * Works with anything that has a `length` property and index access properties, including NodeList.
+ *
+ * @template {unknown} T
+ * @param {Array<T> | ({length:number, [number]: T})} list
+ * @param {function (item: T, index: number, list:Array<T> | ({length:number, [number]: T})):boolean} predicate
+ * @param {Partial<Pick<ArrayConstructor['prototype'], 'find'>>?} ac `Array.prototype` by default,
+ * 				allows injecting a custom implementation in tests
+ * @returns {T | undefined}
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
+ * @see https://tc39.es/ecma262/multipage/indexed-collections.html#sec-array.prototype.find
+ */
+function find(list, predicate, ac) {
+	if (ac === undefined) {
+		ac = Array.prototype;
+	}
+	if (list && typeof ac.find === 'function') {
+		return ac.find.call(list, predicate);
+	}
+	for (var i = 0; i < list.length; i++) {
+		if (Object.prototype.hasOwnProperty.call(list, i)) {
+			var item = list[i];
+			if (predicate.call(undefined, item, i, list)) {
+				return item;
+			}
+		}
+	}
+}
+
+/**
+ * "Shallow freezes" an object to render it immutable.
+ * Uses `Object.freeze` if available,
+ * otherwise the immutability is only in the type.
+ *
+ * Is used to create "enum like" objects.
+ *
+ * @template T
+ * @param {T} object the object to freeze
+ * @param {Pick<ObjectConstructor, 'freeze'> = Object} oc `Object` by default,
+ * 				allows to inject custom object constructor for tests
+ * @returns {Readonly<T>}
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
+ */
+function freeze(object, oc) {
+	if (oc === undefined) {
+		oc = Object
+	}
+	return oc && typeof oc.freeze === 'function' ? oc.freeze(object) : object
+}
+
+/**
+ * Since we can not rely on `Object.assign` we provide a simplified version
+ * that is sufficient for our needs.
+ *
+ * @param {Object} target
+ * @param {Object | null | undefined} source
+ *
+ * @returns {Object} target
+ * @throws TypeError if target is not an object
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
+ * @see https://tc39.es/ecma262/multipage/fundamental-objects.html#sec-object.assign
+ */
+function assign(target, source) {
+	if (target === null || typeof target !== 'object') {
+		throw new TypeError('target is not an object')
+	}
+	for (var key in source) {
+		if (Object.prototype.hasOwnProperty.call(source, key)) {
+			target[key] = source[key]
+		}
+	}
+	return target
+}
+
+/**
+ * All mime types that are allowed as input to `DOMParser.parseFromString`
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString#Argument02 MDN
+ * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#domparsersupportedtype WHATWG HTML Spec
+ * @see DOMParser.prototype.parseFromString
+ */
+var MIME_TYPE = freeze({
+	/**
+	 * `text/html`, the only mime type that triggers treating an XML document as HTML.
+	 *
+	 * @see DOMParser.SupportedType.isHTML
+	 * @see https://www.iana.org/assignments/media-types/text/html IANA MimeType registration
+	 * @see https://en.wikipedia.org/wiki/HTML Wikipedia
+	 * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString MDN
+	 * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-domparser-parsefromstring WHATWG HTML Spec
+	 */
+	HTML: 'text/html',
+
+	/**
+	 * Helper method to check a mime type if it indicates an HTML document
+	 *
+	 * @param {string} [value]
+	 * @returns {boolean}
+	 *
+	 * @see https://www.iana.org/assignments/media-types/text/html IANA MimeType registration
+	 * @see https://en.wikipedia.org/wiki/HTML Wikipedia
+	 * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString MDN
+	 * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-domparser-parsefromstring 	 */
+	isHTML: function (value) {
+		return value === MIME_TYPE.HTML
+	},
+
+	/**
+	 * `application/xml`, the standard mime type for XML documents.
+	 *
+	 * @see https://www.iana.org/assignments/media-types/application/xml IANA MimeType registration
+	 * @see https://tools.ietf.org/html/rfc7303#section-9.1 RFC 7303
+	 * @see https://en.wikipedia.org/wiki/XML_and_MIME Wikipedia
+	 */
+	XML_APPLICATION: 'application/xml',
+
+	/**
+	 * `text/html`, an alias for `application/xml`.
+	 *
+	 * @see https://tools.ietf.org/html/rfc7303#section-9.2 RFC 7303
+	 * @see https://www.iana.org/assignments/media-types/text/xml IANA MimeType registration
+	 * @see https://en.wikipedia.org/wiki/XML_and_MIME Wikipedia
+	 */
+	XML_TEXT: 'text/xml',
+
+	/**
+	 * `application/xhtml+xml`, indicates an XML document that has the default HTML namespace,
+	 * but is parsed as an XML document.
+	 *
+	 * @see https://www.iana.org/assignments/media-types/application/xhtml+xml IANA MimeType registration
+	 * @see https://dom.spec.whatwg.org/#dom-domimplementation-createdocument WHATWG DOM Spec
+	 * @see https://en.wikipedia.org/wiki/XHTML Wikipedia
+	 */
+	XML_XHTML_APPLICATION: 'application/xhtml+xml',
+
+	/**
+	 * `image/svg+xml`,
+	 *
+	 * @see https://www.iana.org/assignments/media-types/image/svg+xml IANA MimeType registration
+	 * @see https://www.w3.org/TR/SVG11/ W3C SVG 1.1
+	 * @see https://en.wikipedia.org/wiki/Scalable_Vector_Graphics Wikipedia
+	 */
+	XML_SVG_IMAGE: 'image/svg+xml',
+})
+
+/**
+ * Namespaces that are used in this code base.
+ *
+ * @see http://www.w3.org/TR/REC-xml-names
+ */
+var NAMESPACE = freeze({
+	/**
+	 * The XHTML namespace.
+	 *
+	 * @see http://www.w3.org/1999/xhtml
+	 */
+	HTML: 'http://www.w3.org/1999/xhtml',
+
+	/**
+	 * Checks if `uri` equals `NAMESPACE.HTML`.
+	 *
+	 * @param {string} [uri]
+	 *
+	 * @see NAMESPACE.HTML
+	 */
+	isHTML: function (uri) {
+		return uri === NAMESPACE.HTML
+	},
+
+	/**
+	 * The SVG namespace.
+	 *
+	 * @see http://www.w3.org/2000/svg
+	 */
+	SVG: 'http://www.w3.org/2000/svg',
+
+	/**
+	 * The `xml:` namespace.
+	 *
+	 * @see http://www.w3.org/XML/1998/namespace
+	 */
+	XML: 'http://www.w3.org/XML/1998/namespace',
+
+	/**
+	 * The `xmlns:` namespace
+	 *
+	 * @see https://www.w3.org/2000/xmlns/
+	 */
+	XMLNS: 'http://www.w3.org/2000/xmlns/',
+})
+
+exports.assign = assign;
+exports.find = find;
+exports.freeze = freeze;
+exports.MIME_TYPE = MIME_TYPE;
+exports.NAMESPACE = NAMESPACE;

+ 322 - 0
node_modules/@xmldom/xmldom/lib/dom-parser.js

@@ -0,0 +1,322 @@
+var conventions = require("./conventions");
+var dom = require('./dom')
+var entities = require('./entities');
+var sax = require('./sax');
+
+var DOMImplementation = dom.DOMImplementation;
+
+var NAMESPACE = conventions.NAMESPACE;
+
+var ParseError = sax.ParseError;
+var XMLReader = sax.XMLReader;
+
+/**
+ * Normalizes line ending according to https://www.w3.org/TR/xml11/#sec-line-ends:
+ *
+ * > XML parsed entities are often stored in computer files which,
+ * > for editing convenience, are organized into lines.
+ * > These lines are typically separated by some combination
+ * > of the characters CARRIAGE RETURN (#xD) and LINE FEED (#xA).
+ * >
+ * > To simplify the tasks of applications, the XML processor must behave
+ * > as if it normalized all line breaks in external parsed entities (including the document entity)
+ * > on input, before parsing, by translating all of the following to a single #xA character:
+ * >
+ * > 1. the two-character sequence #xD #xA
+ * > 2. the two-character sequence #xD #x85
+ * > 3. the single character #x85
+ * > 4. the single character #x2028
+ * > 5. any #xD character that is not immediately followed by #xA or #x85.
+ *
+ * @param {string} input
+ * @returns {string}
+ */
+function normalizeLineEndings(input) {
+	return input
+		.replace(/\r[\n\u0085]/g, '\n')
+		.replace(/[\r\u0085\u2028]/g, '\n')
+}
+
+/**
+ * @typedef Locator
+ * @property {number} [columnNumber]
+ * @property {number} [lineNumber]
+ */
+
+/**
+ * @typedef DOMParserOptions
+ * @property {DOMHandler} [domBuilder]
+ * @property {Function} [errorHandler]
+ * @property {(string) => string} [normalizeLineEndings] used to replace line endings before parsing
+ * 						defaults to `normalizeLineEndings`
+ * @property {Locator} [locator]
+ * @property {Record<string, string>} [xmlns]
+ *
+ * @see normalizeLineEndings
+ */
+
+/**
+ * The DOMParser interface provides the ability to parse XML or HTML source code
+ * from a string into a DOM `Document`.
+ *
+ * _xmldom is different from the spec in that it allows an `options` parameter,
+ * to override the default behavior._
+ *
+ * @param {DOMParserOptions} [options]
+ * @constructor
+ *
+ * @see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser
+ * @see https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#dom-parsing-and-serialization
+ */
+function DOMParser(options){
+	this.options = options ||{locator:{}};
+}
+
+DOMParser.prototype.parseFromString = function(source,mimeType){
+	var options = this.options;
+	var sax =  new XMLReader();
+	var domBuilder = options.domBuilder || new DOMHandler();//contentHandler and LexicalHandler
+	var errorHandler = options.errorHandler;
+	var locator = options.locator;
+	var defaultNSMap = options.xmlns||{};
+	var isHTML = /\/x?html?$/.test(mimeType);//mimeType.toLowerCase().indexOf('html') > -1;
+  	var entityMap = isHTML ? entities.HTML_ENTITIES : entities.XML_ENTITIES;
+	if(locator){
+		domBuilder.setDocumentLocator(locator)
+	}
+
+	sax.errorHandler = buildErrorHandler(errorHandler,domBuilder,locator);
+	sax.domBuilder = options.domBuilder || domBuilder;
+	if(isHTML){
+		defaultNSMap[''] = NAMESPACE.HTML;
+	}
+	defaultNSMap.xml = defaultNSMap.xml || NAMESPACE.XML;
+	var normalize = options.normalizeLineEndings || normalizeLineEndings;
+	if (source && typeof source === 'string') {
+		sax.parse(
+			normalize(source),
+			defaultNSMap,
+			entityMap
+		)
+	} else {
+		sax.errorHandler.error('invalid doc source')
+	}
+	return domBuilder.doc;
+}
+function buildErrorHandler(errorImpl,domBuilder,locator){
+	if(!errorImpl){
+		if(domBuilder instanceof DOMHandler){
+			return domBuilder;
+		}
+		errorImpl = domBuilder ;
+	}
+	var errorHandler = {}
+	var isCallback = errorImpl instanceof Function;
+	locator = locator||{}
+	function build(key){
+		var fn = errorImpl[key];
+		if(!fn && isCallback){
+			fn = errorImpl.length == 2?function(msg){errorImpl(key,msg)}:errorImpl;
+		}
+		errorHandler[key] = fn && function(msg){
+			fn('[xmldom '+key+']\t'+msg+_locator(locator));
+		}||function(){};
+	}
+	build('warning');
+	build('error');
+	build('fatalError');
+	return errorHandler;
+}
+
+//console.log('#\n\n\n\n\n\n\n####')
+/**
+ * +ContentHandler+ErrorHandler
+ * +LexicalHandler+EntityResolver2
+ * -DeclHandler-DTDHandler
+ *
+ * DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler
+ * DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2
+ * @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html
+ */
+function DOMHandler() {
+    this.cdata = false;
+}
+function position(locator,node){
+	node.lineNumber = locator.lineNumber;
+	node.columnNumber = locator.columnNumber;
+}
+/**
+ * @see org.xml.sax.ContentHandler#startDocument
+ * @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html
+ */
+DOMHandler.prototype = {
+	startDocument : function() {
+    	this.doc = new DOMImplementation().createDocument(null, null, null);
+    	if (this.locator) {
+        	this.doc.documentURI = this.locator.systemId;
+    	}
+	},
+	startElement:function(namespaceURI, localName, qName, attrs) {
+		var doc = this.doc;
+	    var el = doc.createElementNS(namespaceURI, qName||localName);
+	    var len = attrs.length;
+	    appendElement(this, el);
+	    this.currentElement = el;
+
+		this.locator && position(this.locator,el)
+	    for (var i = 0 ; i < len; i++) {
+	        var namespaceURI = attrs.getURI(i);
+	        var value = attrs.getValue(i);
+	        var qName = attrs.getQName(i);
+			var attr = doc.createAttributeNS(namespaceURI, qName);
+			this.locator &&position(attrs.getLocator(i),attr);
+			attr.value = attr.nodeValue = value;
+			el.setAttributeNode(attr)
+	    }
+	},
+	endElement:function(namespaceURI, localName, qName) {
+		var current = this.currentElement
+		var tagName = current.tagName;
+		this.currentElement = current.parentNode;
+	},
+	startPrefixMapping:function(prefix, uri) {
+	},
+	endPrefixMapping:function(prefix) {
+	},
+	processingInstruction:function(target, data) {
+	    var ins = this.doc.createProcessingInstruction(target, data);
+	    this.locator && position(this.locator,ins)
+	    appendElement(this, ins);
+	},
+	ignorableWhitespace:function(ch, start, length) {
+	},
+	characters:function(chars, start, length) {
+		chars = _toString.apply(this,arguments)
+		//console.log(chars)
+		if(chars){
+			if (this.cdata) {
+				var charNode = this.doc.createCDATASection(chars);
+			} else {
+				var charNode = this.doc.createTextNode(chars);
+			}
+			if(this.currentElement){
+				this.currentElement.appendChild(charNode);
+			}else if(/^\s*$/.test(chars)){
+				this.doc.appendChild(charNode);
+				//process xml
+			}
+			this.locator && position(this.locator,charNode)
+		}
+	},
+	skippedEntity:function(name) {
+	},
+	endDocument:function() {
+		this.doc.normalize();
+	},
+	setDocumentLocator:function (locator) {
+	    if(this.locator = locator){// && !('lineNumber' in locator)){
+	    	locator.lineNumber = 0;
+	    }
+	},
+	//LexicalHandler
+	comment:function(chars, start, length) {
+		chars = _toString.apply(this,arguments)
+	    var comm = this.doc.createComment(chars);
+	    this.locator && position(this.locator,comm)
+	    appendElement(this, comm);
+	},
+
+	startCDATA:function() {
+	    //used in characters() methods
+	    this.cdata = true;
+	},
+	endCDATA:function() {
+	    this.cdata = false;
+	},
+
+	startDTD:function(name, publicId, systemId) {
+		var impl = this.doc.implementation;
+	    if (impl && impl.createDocumentType) {
+	        var dt = impl.createDocumentType(name, publicId, systemId);
+	        this.locator && position(this.locator,dt)
+	        appendElement(this, dt);
+					this.doc.doctype = dt;
+	    }
+	},
+	/**
+	 * @see org.xml.sax.ErrorHandler
+	 * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
+	 */
+	warning:function(error) {
+		console.warn('[xmldom warning]\t'+error,_locator(this.locator));
+	},
+	error:function(error) {
+		console.error('[xmldom error]\t'+error,_locator(this.locator));
+	},
+	fatalError:function(error) {
+		throw new ParseError(error, this.locator);
+	}
+}
+function _locator(l){
+	if(l){
+		return '\n@'+(l.systemId ||'')+'#[line:'+l.lineNumber+',col:'+l.columnNumber+']'
+	}
+}
+function _toString(chars,start,length){
+	if(typeof chars == 'string'){
+		return chars.substr(start,length)
+	}else{//java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)")
+		if(chars.length >= start+length || start){
+			return new java.lang.String(chars,start,length)+'';
+		}
+		return chars;
+	}
+}
+
+/*
+ * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html
+ * used method of org.xml.sax.ext.LexicalHandler:
+ *  #comment(chars, start, length)
+ *  #startCDATA()
+ *  #endCDATA()
+ *  #startDTD(name, publicId, systemId)
+ *
+ *
+ * IGNORED method of org.xml.sax.ext.LexicalHandler:
+ *  #endDTD()
+ *  #startEntity(name)
+ *  #endEntity(name)
+ *
+ *
+ * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html
+ * IGNORED method of org.xml.sax.ext.DeclHandler
+ * 	#attributeDecl(eName, aName, type, mode, value)
+ *  #elementDecl(name, model)
+ *  #externalEntityDecl(name, publicId, systemId)
+ *  #internalEntityDecl(name, value)
+ * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html
+ * IGNORED method of org.xml.sax.EntityResolver2
+ *  #resolveEntity(String name,String publicId,String baseURI,String systemId)
+ *  #resolveEntity(publicId, systemId)
+ *  #getExternalSubset(name, baseURI)
+ * @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html
+ * IGNORED method of org.xml.sax.DTDHandler
+ *  #notationDecl(name, publicId, systemId) {};
+ *  #unparsedEntityDecl(name, publicId, systemId, notationName) {};
+ */
+"endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g,function(key){
+	DOMHandler.prototype[key] = function(){return null}
+})
+
+/* Private static helpers treated below as private instance methods, so don't need to add these to the public API; we might use a Relator to also get rid of non-standard public properties */
+function appendElement (hander,node) {
+    if (!hander.currentElement) {
+        hander.doc.appendChild(node);
+    } else {
+        hander.currentElement.appendChild(node);
+    }
+}//appendChild and setAttributeNS are preformance key
+
+exports.__DOMHandler = DOMHandler;
+exports.normalizeLineEndings = normalizeLineEndings;
+exports.DOMParser = DOMParser;

File diff suppressed because it is too large
+ 1840 - 0
node_modules/@xmldom/xmldom/lib/dom.js


File diff suppressed because it is too large
+ 2166 - 0
node_modules/@xmldom/xmldom/lib/entities.js


+ 4 - 0
node_modules/@xmldom/xmldom/lib/index.js

@@ -0,0 +1,4 @@
+var dom = require('./dom')
+exports.DOMImplementation = dom.DOMImplementation
+exports.XMLSerializer = dom.XMLSerializer
+exports.DOMParser = require('./dom-parser').DOMParser

+ 662 - 0
node_modules/@xmldom/xmldom/lib/sax.js

@@ -0,0 +1,662 @@
+var NAMESPACE = require("./conventions").NAMESPACE;
+
+//[4]   	NameStartChar	   ::=   	":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
+//[4a]   	NameChar	   ::=   	NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
+//[5]   	Name	   ::=   	NameStartChar (NameChar)*
+var nameStartChar = /[A-Z_a-z\xC0-\xD6\xD8-\xF6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]///\u10000-\uEFFFF
+var nameChar = new RegExp("[\\-\\.0-9"+nameStartChar.source.slice(1,-1)+"\\u00B7\\u0300-\\u036F\\u203F-\\u2040]");
+var tagNamePattern = new RegExp('^'+nameStartChar.source+nameChar.source+'*(?:\:'+nameStartChar.source+nameChar.source+'*)?$');
+//var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/
+//var handlers = 'resolveEntity,getExternalSubset,characters,endDocument,endElement,endPrefixMapping,ignorableWhitespace,processingInstruction,setDocumentLocator,skippedEntity,startDocument,startElement,startPrefixMapping,notationDecl,unparsedEntityDecl,error,fatalError,warning,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,comment,endCDATA,endDTD,endEntity,startCDATA,startDTD,startEntity'.split(',')
+
+//S_TAG,	S_ATTR,	S_EQ,	S_ATTR_NOQUOT_VALUE
+//S_ATTR_SPACE,	S_ATTR_END,	S_TAG_SPACE, S_TAG_CLOSE
+var S_TAG = 0;//tag name offerring
+var S_ATTR = 1;//attr name offerring
+var S_ATTR_SPACE=2;//attr name end and space offer
+var S_EQ = 3;//=space?
+var S_ATTR_NOQUOT_VALUE = 4;//attr value(no quot value only)
+var S_ATTR_END = 5;//attr value end and no space(quot end)
+var S_TAG_SPACE = 6;//(attr value end || tag end ) && (space offer)
+var S_TAG_CLOSE = 7;//closed el<el />
+
+/**
+ * Creates an error that will not be caught by XMLReader aka the SAX parser.
+ *
+ * @param {string} message
+ * @param {any?} locator Optional, can provide details about the location in the source
+ * @constructor
+ */
+function ParseError(message, locator) {
+	this.message = message
+	this.locator = locator
+	if(Error.captureStackTrace) Error.captureStackTrace(this, ParseError);
+}
+ParseError.prototype = new Error();
+ParseError.prototype.name = ParseError.name
+
+function XMLReader(){
+
+}
+
+XMLReader.prototype = {
+	parse:function(source,defaultNSMap,entityMap){
+		var domBuilder = this.domBuilder;
+		domBuilder.startDocument();
+		_copy(defaultNSMap ,defaultNSMap = {})
+		parse(source,defaultNSMap,entityMap,
+				domBuilder,this.errorHandler);
+		domBuilder.endDocument();
+	}
+}
+function parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){
+	function fixedFromCharCode(code) {
+		// String.prototype.fromCharCode does not supports
+		// > 2 bytes unicode chars directly
+		if (code > 0xffff) {
+			code -= 0x10000;
+			var surrogate1 = 0xd800 + (code >> 10)
+				, surrogate2 = 0xdc00 + (code & 0x3ff);
+
+			return String.fromCharCode(surrogate1, surrogate2);
+		} else {
+			return String.fromCharCode(code);
+		}
+	}
+	function entityReplacer(a){
+		var k = a.slice(1,-1);
+		if (Object.hasOwnProperty.call(entityMap, k)) {
+			return entityMap[k];
+		}else if(k.charAt(0) === '#'){
+			return fixedFromCharCode(parseInt(k.substr(1).replace('x','0x')))
+		}else{
+			errorHandler.error('entity not found:'+a);
+			return a;
+		}
+	}
+	function appendText(end){//has some bugs
+		if(end>start){
+			var xt = source.substring(start,end).replace(/&#?\w+;/g,entityReplacer);
+			locator&&position(start);
+			domBuilder.characters(xt,0,end-start);
+			start = end
+		}
+	}
+	function position(p,m){
+		while(p>=lineEnd && (m = linePattern.exec(source))){
+			lineStart = m.index;
+			lineEnd = lineStart + m[0].length;
+			locator.lineNumber++;
+			//console.log('line++:',locator,startPos,endPos)
+		}
+		locator.columnNumber = p-lineStart+1;
+	}
+	var lineStart = 0;
+	var lineEnd = 0;
+	var linePattern = /.*(?:\r\n?|\n)|.*$/g
+	var locator = domBuilder.locator;
+
+	var parseStack = [{currentNSMap:defaultNSMapCopy}]
+	var closeMap = {};
+	var start = 0;
+	while(true){
+		try{
+			var tagStart = source.indexOf('<',start);
+			if(tagStart<0){
+				if(!source.substr(start).match(/^\s*$/)){
+					var doc = domBuilder.doc;
+	    			var text = doc.createTextNode(source.substr(start));
+	    			doc.appendChild(text);
+	    			domBuilder.currentElement = text;
+				}
+				return;
+			}
+			if(tagStart>start){
+				appendText(tagStart);
+			}
+			switch(source.charAt(tagStart+1)){
+			case '/':
+				var end = source.indexOf('>',tagStart+3);
+				var tagName = source.substring(tagStart + 2, end).replace(/[ \t\n\r]+$/g, '');
+				var config = parseStack.pop();
+				if(end<0){
+
+	        		tagName = source.substring(tagStart+2).replace(/[\s<].*/,'');
+	        		errorHandler.error("end tag name: "+tagName+' is not complete:'+config.tagName);
+	        		end = tagStart+1+tagName.length;
+	        	}else if(tagName.match(/\s</)){
+	        		tagName = tagName.replace(/[\s<].*/,'');
+	        		errorHandler.error("end tag name: "+tagName+' maybe not complete');
+	        		end = tagStart+1+tagName.length;
+				}
+				var localNSMap = config.localNSMap;
+				var endMatch = config.tagName == tagName;
+				var endIgnoreCaseMach = endMatch || config.tagName&&config.tagName.toLowerCase() == tagName.toLowerCase()
+		        if(endIgnoreCaseMach){
+		        	domBuilder.endElement(config.uri,config.localName,tagName);
+					if(localNSMap){
+						for (var prefix in localNSMap) {
+							if (Object.prototype.hasOwnProperty.call(localNSMap, prefix)) {
+								domBuilder.endPrefixMapping(prefix);
+							}
+						}
+					}
+					if(!endMatch){
+		            	errorHandler.fatalError("end tag name: "+tagName+' is not match the current start tagName:'+config.tagName ); // No known test case
+					}
+		        }else{
+		        	parseStack.push(config)
+		        }
+
+				end++;
+				break;
+				// end elment
+			case '?':// <?...?>
+				locator&&position(tagStart);
+				end = parseInstruction(source,tagStart,domBuilder);
+				break;
+			case '!':// <!doctype,<![CDATA,<!--
+				locator&&position(tagStart);
+				end = parseDCC(source,tagStart,domBuilder,errorHandler);
+				break;
+			default:
+				locator&&position(tagStart);
+				var el = new ElementAttributes();
+				var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
+				//elStartEnd
+				var end = parseElementStartPart(source,tagStart,el,currentNSMap,entityReplacer,errorHandler);
+				var len = el.length;
+
+
+				if(!el.closed && fixSelfClosed(source,end,el.tagName,closeMap)){
+					el.closed = true;
+					if(!entityMap.nbsp){
+						errorHandler.warning('unclosed xml attribute');
+					}
+				}
+				if(locator && len){
+					var locator2 = copyLocator(locator,{});
+					//try{//attribute position fixed
+					for(var i = 0;i<len;i++){
+						var a = el[i];
+						position(a.offset);
+						a.locator = copyLocator(locator,{});
+					}
+					domBuilder.locator = locator2
+					if(appendElement(el,domBuilder,currentNSMap)){
+						parseStack.push(el)
+					}
+					domBuilder.locator = locator;
+				}else{
+					if(appendElement(el,domBuilder,currentNSMap)){
+						parseStack.push(el)
+					}
+				}
+
+				if (NAMESPACE.isHTML(el.uri) && !el.closed) {
+					end = parseHtmlSpecialContent(source,end,el.tagName,entityReplacer,domBuilder)
+				} else {
+					end++;
+				}
+			}
+		}catch(e){
+			if (e instanceof ParseError) {
+				throw e;
+			}
+			errorHandler.error('element parse error: '+e)
+			end = -1;
+		}
+		if(end>start){
+			start = end;
+		}else{
+			//TODO: 这里有可能sax回退,有位置错误风险
+			appendText(Math.max(tagStart,start)+1);
+		}
+	}
+}
+function copyLocator(f,t){
+	t.lineNumber = f.lineNumber;
+	t.columnNumber = f.columnNumber;
+	return t;
+}
+
+/**
+ * @see #appendElement(source,elStartEnd,el,selfClosed,entityReplacer,domBuilder,parseStack);
+ * @return end of the elementStartPart(end of elementEndPart for selfClosed el)
+ */
+function parseElementStartPart(source,start,el,currentNSMap,entityReplacer,errorHandler){
+
+	/**
+	 * @param {string} qname
+	 * @param {string} value
+	 * @param {number} startIndex
+	 */
+	function addAttribute(qname, value, startIndex) {
+		if (el.attributeNames.hasOwnProperty(qname)) {
+			errorHandler.fatalError('Attribute ' + qname + ' redefined')
+		}
+		el.addValue(
+			qname,
+			// @see https://www.w3.org/TR/xml/#AVNormalize
+			// since the xmldom sax parser does not "interpret" DTD the following is not implemented:
+			// - recursive replacement of (DTD) entity references
+			// - trimming and collapsing multiple spaces into a single one for attributes that are not of type CDATA
+			value.replace(/[\t\n\r]/g, ' ').replace(/&#?\w+;/g, entityReplacer),
+			startIndex
+		)
+	}
+	var attrName;
+	var value;
+	var p = ++start;
+	var s = S_TAG;//status
+	while(true){
+		var c = source.charAt(p);
+		switch(c){
+		case '=':
+			if(s === S_ATTR){//attrName
+				attrName = source.slice(start,p);
+				s = S_EQ;
+			}else if(s === S_ATTR_SPACE){
+				s = S_EQ;
+			}else{
+				//fatalError: equal must after attrName or space after attrName
+				throw new Error('attribute equal must after attrName'); // No known test case
+			}
+			break;
+		case '\'':
+		case '"':
+			if(s === S_EQ || s === S_ATTR //|| s == S_ATTR_SPACE
+				){//equal
+				if(s === S_ATTR){
+					errorHandler.warning('attribute value must after "="')
+					attrName = source.slice(start,p)
+				}
+				start = p+1;
+				p = source.indexOf(c,start)
+				if(p>0){
+					value = source.slice(start, p);
+					addAttribute(attrName, value, start-1);
+					s = S_ATTR_END;
+				}else{
+					//fatalError: no end quot match
+					throw new Error('attribute value no end \''+c+'\' match');
+				}
+			}else if(s == S_ATTR_NOQUOT_VALUE){
+				value = source.slice(start, p);
+				addAttribute(attrName, value, start);
+				errorHandler.warning('attribute "'+attrName+'" missed start quot('+c+')!!');
+				start = p+1;
+				s = S_ATTR_END
+			}else{
+				//fatalError: no equal before
+				throw new Error('attribute value must after "="'); // No known test case
+			}
+			break;
+		case '/':
+			switch(s){
+			case S_TAG:
+				el.setTagName(source.slice(start,p));
+			case S_ATTR_END:
+			case S_TAG_SPACE:
+			case S_TAG_CLOSE:
+				s =S_TAG_CLOSE;
+				el.closed = true;
+			case S_ATTR_NOQUOT_VALUE:
+			case S_ATTR:
+				break;
+				case S_ATTR_SPACE:
+					el.closed = true;
+				break;
+			//case S_EQ:
+			default:
+				throw new Error("attribute invalid close char('/')") // No known test case
+			}
+			break;
+		case ''://end document
+			errorHandler.error('unexpected end of input');
+			if(s == S_TAG){
+				el.setTagName(source.slice(start,p));
+			}
+			return p;
+		case '>':
+			switch(s){
+			case S_TAG:
+				el.setTagName(source.slice(start,p));
+			case S_ATTR_END:
+			case S_TAG_SPACE:
+			case S_TAG_CLOSE:
+				break;//normal
+			case S_ATTR_NOQUOT_VALUE://Compatible state
+			case S_ATTR:
+				value = source.slice(start,p);
+				if(value.slice(-1) === '/'){
+					el.closed  = true;
+					value = value.slice(0,-1)
+				}
+			case S_ATTR_SPACE:
+				if(s === S_ATTR_SPACE){
+					value = attrName;
+				}
+				if(s == S_ATTR_NOQUOT_VALUE){
+					errorHandler.warning('attribute "'+value+'" missed quot(")!');
+					addAttribute(attrName, value, start)
+				}else{
+					if(!NAMESPACE.isHTML(currentNSMap['']) || !value.match(/^(?:disabled|checked|selected)$/i)){
+						errorHandler.warning('attribute "'+value+'" missed value!! "'+value+'" instead!!')
+					}
+					addAttribute(value, value, start)
+				}
+				break;
+			case S_EQ:
+				throw new Error('attribute value missed!!');
+			}
+//			console.log(tagName,tagNamePattern,tagNamePattern.test(tagName))
+			return p;
+		/*xml space '\x20' | #x9 | #xD | #xA; */
+		case '\u0080':
+			c = ' ';
+		default:
+			if(c<= ' '){//space
+				switch(s){
+				case S_TAG:
+					el.setTagName(source.slice(start,p));//tagName
+					s = S_TAG_SPACE;
+					break;
+				case S_ATTR:
+					attrName = source.slice(start,p)
+					s = S_ATTR_SPACE;
+					break;
+				case S_ATTR_NOQUOT_VALUE:
+					var value = source.slice(start, p);
+					errorHandler.warning('attribute "'+value+'" missed quot(")!!');
+					addAttribute(attrName, value, start)
+				case S_ATTR_END:
+					s = S_TAG_SPACE;
+					break;
+				//case S_TAG_SPACE:
+				//case S_EQ:
+				//case S_ATTR_SPACE:
+				//	void();break;
+				//case S_TAG_CLOSE:
+					//ignore warning
+				}
+			}else{//not space
+//S_TAG,	S_ATTR,	S_EQ,	S_ATTR_NOQUOT_VALUE
+//S_ATTR_SPACE,	S_ATTR_END,	S_TAG_SPACE, S_TAG_CLOSE
+				switch(s){
+				//case S_TAG:void();break;
+				//case S_ATTR:void();break;
+				//case S_ATTR_NOQUOT_VALUE:void();break;
+				case S_ATTR_SPACE:
+					var tagName =  el.tagName;
+					if (!NAMESPACE.isHTML(currentNSMap['']) || !attrName.match(/^(?:disabled|checked|selected)$/i)) {
+						errorHandler.warning('attribute "'+attrName+'" missed value!! "'+attrName+'" instead2!!')
+					}
+					addAttribute(attrName, attrName, start);
+					start = p;
+					s = S_ATTR;
+					break;
+				case S_ATTR_END:
+					errorHandler.warning('attribute space is required"'+attrName+'"!!')
+				case S_TAG_SPACE:
+					s = S_ATTR;
+					start = p;
+					break;
+				case S_EQ:
+					s = S_ATTR_NOQUOT_VALUE;
+					start = p;
+					break;
+				case S_TAG_CLOSE:
+					throw new Error("elements closed character '/' and '>' must be connected to");
+				}
+			}
+		}//end outer switch
+		//console.log('p++',p)
+		p++;
+	}
+}
+/**
+ * @return true if has new namespace define
+ */
+function appendElement(el,domBuilder,currentNSMap){
+	var tagName = el.tagName;
+	var localNSMap = null;
+	//var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
+	var i = el.length;
+	while(i--){
+		var a = el[i];
+		var qName = a.qName;
+		var value = a.value;
+		var nsp = qName.indexOf(':');
+		if(nsp>0){
+			var prefix = a.prefix = qName.slice(0,nsp);
+			var localName = qName.slice(nsp+1);
+			var nsPrefix = prefix === 'xmlns' && localName
+		}else{
+			localName = qName;
+			prefix = null
+			nsPrefix = qName === 'xmlns' && ''
+		}
+		//can not set prefix,because prefix !== ''
+		a.localName = localName ;
+		//prefix == null for no ns prefix attribute
+		if(nsPrefix !== false){//hack!!
+			if(localNSMap == null){
+				localNSMap = {}
+				//console.log(currentNSMap,0)
+				_copy(currentNSMap,currentNSMap={})
+				//console.log(currentNSMap,1)
+			}
+			currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value;
+			a.uri = NAMESPACE.XMLNS
+			domBuilder.startPrefixMapping(nsPrefix, value)
+		}
+	}
+	var i = el.length;
+	while(i--){
+		a = el[i];
+		var prefix = a.prefix;
+		if(prefix){//no prefix attribute has no namespace
+			if(prefix === 'xml'){
+				a.uri = NAMESPACE.XML;
+			}if(prefix !== 'xmlns'){
+				a.uri = currentNSMap[prefix || '']
+
+				//{console.log('###'+a.qName,domBuilder.locator.systemId+'',currentNSMap,a.uri)}
+			}
+		}
+	}
+	var nsp = tagName.indexOf(':');
+	if(nsp>0){
+		prefix = el.prefix = tagName.slice(0,nsp);
+		localName = el.localName = tagName.slice(nsp+1);
+	}else{
+		prefix = null;//important!!
+		localName = el.localName = tagName;
+	}
+	//no prefix element has default namespace
+	var ns = el.uri = currentNSMap[prefix || ''];
+	domBuilder.startElement(ns,localName,tagName,el);
+	//endPrefixMapping and startPrefixMapping have not any help for dom builder
+	//localNSMap = null
+	if(el.closed){
+		domBuilder.endElement(ns,localName,tagName);
+		if(localNSMap){
+			for (prefix in localNSMap) {
+				if (Object.prototype.hasOwnProperty.call(localNSMap, prefix)) {
+					domBuilder.endPrefixMapping(prefix);
+				}
+			}
+		}
+	}else{
+		el.currentNSMap = currentNSMap;
+		el.localNSMap = localNSMap;
+		//parseStack.push(el);
+		return true;
+	}
+}
+function parseHtmlSpecialContent(source,elStartEnd,tagName,entityReplacer,domBuilder){
+	if(/^(?:script|textarea)$/i.test(tagName)){
+		var elEndStart =  source.indexOf('</'+tagName+'>',elStartEnd);
+		var text = source.substring(elStartEnd+1,elEndStart);
+		if(/[&<]/.test(text)){
+			if(/^script$/i.test(tagName)){
+				//if(!/\]\]>/.test(text)){
+					//lexHandler.startCDATA();
+					domBuilder.characters(text,0,text.length);
+					//lexHandler.endCDATA();
+					return elEndStart;
+				//}
+			}//}else{//text area
+				text = text.replace(/&#?\w+;/g,entityReplacer);
+				domBuilder.characters(text,0,text.length);
+				return elEndStart;
+			//}
+
+		}
+	}
+	return elStartEnd+1;
+}
+function fixSelfClosed(source,elStartEnd,tagName,closeMap){
+	//if(tagName in closeMap){
+	var pos = closeMap[tagName];
+	if(pos == null){
+		//console.log(tagName)
+		pos =  source.lastIndexOf('</'+tagName+'>')
+		if(pos<elStartEnd){//忘记闭合
+			pos = source.lastIndexOf('</'+tagName)
+		}
+		closeMap[tagName] =pos
+	}
+	return pos<elStartEnd;
+	//}
+}
+
+function _copy (source, target) {
+	for (var n in source) {
+		if (Object.prototype.hasOwnProperty.call(source, n)) {
+			target[n] = source[n];
+		}
+	}
+}
+
+function parseDCC(source,start,domBuilder,errorHandler){//sure start with '<!'
+	var next= source.charAt(start+2)
+	switch(next){
+	case '-':
+		if(source.charAt(start + 3) === '-'){
+			var end = source.indexOf('-->',start+4);
+			//append comment source.substring(4,end)//<!--
+			if(end>start){
+				domBuilder.comment(source,start+4,end-start-4);
+				return end+3;
+			}else{
+				errorHandler.error("Unclosed comment");
+				return -1;
+			}
+		}else{
+			//error
+			return -1;
+		}
+	default:
+		if(source.substr(start+3,6) == 'CDATA['){
+			var end = source.indexOf(']]>',start+9);
+			domBuilder.startCDATA();
+			domBuilder.characters(source,start+9,end-start-9);
+			domBuilder.endCDATA()
+			return end+3;
+		}
+		//<!DOCTYPE
+		//startDTD(java.lang.String name, java.lang.String publicId, java.lang.String systemId)
+		var matchs = split(source,start);
+		var len = matchs.length;
+		if(len>1 && /!doctype/i.test(matchs[0][0])){
+			var name = matchs[1][0];
+			var pubid = false;
+			var sysid = false;
+			if(len>3){
+				if(/^public$/i.test(matchs[2][0])){
+					pubid = matchs[3][0];
+					sysid = len>4 && matchs[4][0];
+				}else if(/^system$/i.test(matchs[2][0])){
+					sysid = matchs[3][0];
+				}
+			}
+			var lastMatch = matchs[len-1]
+			domBuilder.startDTD(name, pubid, sysid);
+			domBuilder.endDTD();
+
+			return lastMatch.index+lastMatch[0].length
+		}
+	}
+	return -1;
+}
+
+
+
+function parseInstruction(source,start,domBuilder){
+	var end = source.indexOf('?>',start);
+	if(end){
+		var match = source.substring(start,end).match(/^<\?(\S*)\s*([\s\S]*?)\s*$/);
+		if(match){
+			var len = match[0].length;
+			domBuilder.processingInstruction(match[1], match[2]) ;
+			return end+2;
+		}else{//error
+			return -1;
+		}
+	}
+	return -1;
+}
+
+function ElementAttributes(){
+	this.attributeNames = {}
+}
+ElementAttributes.prototype = {
+	setTagName:function(tagName){
+		if(!tagNamePattern.test(tagName)){
+			throw new Error('invalid tagName:'+tagName)
+		}
+		this.tagName = tagName
+	},
+	addValue:function(qName, value, offset) {
+		if(!tagNamePattern.test(qName)){
+			throw new Error('invalid attribute:'+qName)
+		}
+		this.attributeNames[qName] = this.length;
+		this[this.length++] = {qName:qName,value:value,offset:offset}
+	},
+	length:0,
+	getLocalName:function(i){return this[i].localName},
+	getLocator:function(i){return this[i].locator},
+	getQName:function(i){return this[i].qName},
+	getURI:function(i){return this[i].uri},
+	getValue:function(i){return this[i].value}
+//	,getIndex:function(uri, localName)){
+//		if(localName){
+//
+//		}else{
+//			var qName = uri
+//		}
+//	},
+//	getValue:function(){return this.getValue(this.getIndex.apply(this,arguments))},
+//	getType:function(uri,localName){}
+//	getType:function(i){},
+}
+
+
+
+function split(source,start){
+	var match;
+	var buf = [];
+	var reg = /'[^']+'|"[^"]+"|[^\s<>\/=]+=?|(\/?\s*>|<)/g;
+	reg.lastIndex = start;
+	reg.exec(source);//skip <
+	while(match = reg.exec(source)){
+		buf.push(match);
+		if(match[1])return buf;
+	}
+}
+
+exports.XMLReader = XMLReader;
+exports.ParseError = ParseError;

+ 71 - 0
node_modules/@xmldom/xmldom/package.json

@@ -0,0 +1,71 @@
+{
+  "name": "@xmldom/xmldom",
+  "version": "0.8.10",
+  "description": "A pure JavaScript W3C standard-based (XML DOM Level 2 Core) DOMParser and XMLSerializer module.",
+  "keywords": [
+    "w3c",
+    "dom",
+    "xml",
+    "parser",
+    "javascript",
+    "DOMParser",
+    "XMLSerializer",
+    "ponyfill"
+  ],
+  "homepage": "https://github.com/xmldom/xmldom",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/xmldom/xmldom.git"
+  },
+  "main": "lib/index.js",
+  "types": "index.d.ts",
+  "files": [
+    "CHANGELOG.md",
+    "LICENSE",
+    "readme.md",
+    "SECURITY.md",
+    "index.d.ts",
+    "lib"
+  ],
+  "scripts": {
+    "lint": "eslint lib test",
+    "format": "prettier --write test",
+    "changelog": "auto-changelog --unreleased-only",
+    "start": "nodemon --watch package.json --watch lib --watch test --exec 'npm --silent run test && npm --silent run lint'",
+    "stryker": "stryker run",
+    "stryker:dry-run": "stryker run -m '' --reporters progress",
+    "test": "jest",
+    "testrelease": "npm test && eslint lib",
+    "version": "./changelog-has-version.sh",
+    "release": "np --no-yarn --test-script testrelease --branch release-0.8.x patch"
+  },
+  "engines": {
+    "node": ">=10.0.0"
+  },
+  "dependencies": {},
+  "devDependencies": {
+    "@stryker-mutator/core": "5.6.1",
+    "auto-changelog": "2.4.0",
+    "eslint": "8.25.0",
+    "eslint-config-prettier": "8.5.0",
+    "eslint-plugin-es5": "1.5.0",
+    "eslint-plugin-prettier": "4.2.1",
+    "get-stream": "6.0.1",
+    "jest": "27.5.1",
+    "nodemon": "2.0.20",
+    "np": "7.6.2",
+    "prettier": "2.7.1",
+    "xmltest": "1.5.0",
+    "yauzl": "2.10.0"
+  },
+  "bugs": {
+    "url": "https://github.com/xmldom/xmldom/issues"
+  },
+  "license": "MIT",
+  "auto-changelog": {
+    "prepend": true,
+    "remote": "upstream",
+    "tagPrefix": "",
+    "template": "./auto-changelog.hbs"
+  }
+}

+ 356 - 0
node_modules/@xmldom/xmldom/readme.md

@@ -0,0 +1,356 @@
+# @xmldom/xmldom
+
+***Since version 0.7.0 this package is published to npm as [`@xmldom/xmldom`](https://www.npmjs.com/package/@xmldom/xmldom) and no longer as [`xmldom`](https://www.npmjs.com/package/xmldom), because [we are no longer able to publish `xmldom`](https://github.com/xmldom/xmldom/issues/271).***  
+*For better readability in the docs we will continue to talk about this library as "xmldom".*
+
+[![license(MIT)](https://img.shields.io/npm/l/@xmldom/xmldom?color=blue&style=flat-square)](https://github.com/xmldom/xmldom/blob/master/LICENSE)
+[![npm](https://img.shields.io/npm/v/@xmldom/xmldom?style=flat-square)](https://www.npmjs.com/package/@xmldom/xmldom)
+[![snyk.io package health](https://snyk.io/advisor/npm-package/@xmldom/xmldom/badge.svg)](https://snyk.io/advisor/npm-package/@xmldom/xmldom)
+[![bug issues](https://img.shields.io/github/issues/xmldom/xmldom/bug?color=red&style=flat-square)](https://github.com/xmldom/xmldom/issues?q=is%3Aissue+is%3Aopen+label%3Abug)
+[![help-wanted issues](https://img.shields.io/github/issues/xmldom/xmldom/help-wanted?color=darkgreen&style=flat-square)](https://github.com/xmldom/xmldom/issues?q=is%3Aissue+is%3Aopen+label%3Ahelp-wanted)
+[![Mutation report](https://img.shields.io/endpoint?style=flat-square&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fxmldom%2Fxmldom%2Fmaster)](https://dashboard.stryker-mutator.io/reports/github.com/xmldom/xmldom/master)
+
+
+xmldom is a javascript [ponyfill](https://ponyfill.com/) to provide the following APIs [that are present in modern browsers](https://caniuse.com/xml-serializer) to other runtimes:
+- convert an XML string into a DOM tree
+  ```
+  new DOMParser().parseFromString(xml, mimeType) => Document
+  ```
+- create, access and modify a DOM tree
+  ```
+  new DOMImplementation().createDocument(...) => Document
+  ```
+- serialize a DOM tree back into an XML string
+  ```
+  new XMLSerializer().serializeToString(node) => string
+  ```
+
+The target runtimes `xmldom` supports are currently Node >= v10 (ES5) and Rhino ([not tested as part of CI](https://github.com/xmldom/xmldom/discussions/214)).
+
+When deciding how to fix bugs or implement features, `xmldom` tries to stay as close  as possible to the various [related specifications/standards](#specs).  
+As indicated by the version starting with `0.`, this implementation is not feature complete and some implemented features differ from what the specifications describe.  
+**Issues and PRs for such differences are always welcome, even when they only provide a failing test case.**
+
+This project was forked from it's [original source](https://github.com/jindw/xmldom) in 2019, more details about that transition can be found in the [CHANGELOG](CHANGELOG.md#maintainer-changes).
+
+## Usage
+
+### Install:
+
+> npm install @xmldom/xmldom
+
+### Example:
+
+[In NodeJS](examples/nodejs/src/index.js)
+```javascript
+const { DOMParser, XMLSerializer } = require('@xmldom/xmldom')
+
+const source = `<xml xmlns="a">
+	<child>test</child>
+	<child/>
+</xml>`
+
+const doc = new DOMParser().parseFromString(source, 'text/xml')
+
+const serialized = new XMLSerializer().serializeToString(doc)
+```
+
+Note: in Typescript ~and ES6~(see #316) you can use the `import` approach, as follows:
+
+```typescript
+import { DOMParser } from '@xmldom/xmldom'
+```
+
+## API Reference
+
+ * [DOMParser](https://developer.mozilla.org/en-US/docs/Web/API/DOMParser):
+
+	```javascript
+	parseFromString(xmlsource,mimeType)
+	```
+	* **options extension** _by xmldom_ (not DOM standard!!)
+
+	```javascript
+	//added the options argument
+	new DOMParser(options)
+	
+	//errorHandler is supported
+	new DOMParser({
+		/**
+		 * locator is always need for error position info
+		 */
+		locator:{},
+		/**
+		 * you can override the errorHandler for xml parser
+		 * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
+		 */
+		errorHandler:{warning:function(w){console.warn(w)},error:callback,fatalError:callback}
+		//only callback model
+		//errorHandler:function(level,msg){console.log(level,msg)}
+	})
+		
+	```
+
+ * [XMLSerializer](https://developer.mozilla.org/en-US/docs/Web/API/XMLSerializer)
+ 
+	```javascript
+	serializeToString(node)
+	```
+### DOM level2 method and attribute:
+
+* [Node](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247)
+
+  readonly class properties (aka `NodeType`),  
+  these can be accessed from any `Node` instance `node`:  
+  `if (node.nodeType === node.ELEMENT_NODE) {...`
+  
+    1. `ELEMENT_NODE` (`1`)
+    2. `ATTRIBUTE_NODE` (`2`)
+    3. `TEXT_NODE` (`3`)
+    4. `CDATA_SECTION_NODE` (`4`)
+    5. `ENTITY_REFERENCE_NODE` (`5`)
+    6. `ENTITY_NODE` (`6`)
+    7. `PROCESSING_INSTRUCTION_NODE` (`7`)
+    8. `COMMENT_NODE` (`8`)
+    9. `DOCUMENT_NODE` (`9`)
+    10. `DOCUMENT_TYPE_NODE` (`10`)
+    11. `DOCUMENT_FRAGMENT_NODE` (`11`)
+    12. `NOTATION_NODE` (`12`)
+  
+  attribute:
+    - `nodeValue` | `prefix`
+  
+  readonly attribute:
+    - `nodeName` | `nodeType` | `parentNode` | `childNodes` | `firstChild` | `lastChild` | `previousSibling` | `nextSibling` | `attributes` | `ownerDocument` | `namespaceURI` | `localName`
+  
+  method:	
+    * `insertBefore(newChild, refChild)`
+    * `replaceChild(newChild, oldChild)`
+    * `removeChild(oldChild)`
+    * `appendChild(newChild)`
+    * `hasChildNodes()`
+    * `cloneNode(deep)`
+    * `normalize()`
+    * `isSupported(feature, version)`
+    * `hasAttributes()`
+* [DOMException](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/ecma-script-binding.html)
+
+  extends the Error type thrown as part of DOM API.
+
+  readonly class properties:
+  - `INDEX_SIZE_ERR` (`1`)
+  - `DOMSTRING_SIZE_ERR` (`2`)
+  - `HIERARCHY_REQUEST_ERR` (`3`)
+  - `WRONG_DOCUMENT_ERR` (`4`)
+  - `INVALID_CHARACTER_ERR` (`5`)
+  - `NO_DATA_ALLOWED_ERR` (`6`)
+  - `NO_MODIFICATION_ALLOWED_ERR` (`7`)
+  - `NOT_FOUND_ERR` (`8`)
+  - `NOT_SUPPORTED_ERR` (`9`)
+  - `INUSE_ATTRIBUTE_ERR` (`10`)
+  - `INVALID_STATE_ERR` (`11`)
+  - `SYNTAX_ERR` (`12`)
+  - `INVALID_MODIFICATION_ERR` (`13`)
+  - `NAMESPACE_ERR` (`14`)
+  - `INVALID_ACCESS_ERR` (`15`)
+   
+  attributes:
+  -  `code` with a value matching one of the above constants.
+
+* [DOMImplementation](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-102161490)
+
+  method:
+  - `hasFeature(feature, version)`
+  - `createDocumentType(qualifiedName, publicId, systemId)`
+  - `createDocument(namespaceURI, qualifiedName, doctype)`
+
+* [Document](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#i-Document) : Node
+		
+  readonly attribute:
+  - `doctype` | `implementation` | `documentElement`
+  
+  method:
+  - `createElement(tagName)`
+  - `createDocumentFragment()`
+  - `createTextNode(data)`
+  - `createComment(data)`
+  - `createCDATASection(data)`
+  - `createProcessingInstruction(target, data)`
+  - `createAttribute(name)`
+  - `createEntityReference(name)`
+  - `getElementsByTagName(tagname)`
+  - `importNode(importedNode, deep)`
+  - `createElementNS(namespaceURI, qualifiedName)`
+  - `createAttributeNS(namespaceURI, qualifiedName)`
+  - `getElementsByTagNameNS(namespaceURI, localName)`
+  - `getElementById(elementId)`
+
+* [DocumentFragment](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-B63ED1A3) : Node
+* [Element](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-745549614) : Node
+		
+  readonly attribute:
+  - `tagName`
+
+  method:
+  - `getAttribute(name)`
+  - `setAttribute(name, value)`
+  - `removeAttribute(name)`
+  - `getAttributeNode(name)`
+  - `setAttributeNode(newAttr)`
+  - `removeAttributeNode(oldAttr)`
+  - `getElementsByTagName(name)`
+  - `getAttributeNS(namespaceURI, localName)`
+  - `setAttributeNS(namespaceURI, qualifiedName, value)`
+  - `removeAttributeNS(namespaceURI, localName)`
+  - `getAttributeNodeNS(namespaceURI, localName)`
+  - `setAttributeNodeNS(newAttr)`
+  - `getElementsByTagNameNS(namespaceURI, localName)`
+  - `hasAttribute(name)`
+  - `hasAttributeNS(namespaceURI, localName)`
+
+* [Attr](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-637646024) : Node
+
+  attribute:
+  - `value`
+
+  readonly attribute:
+  - `name` | `specified` | `ownerElement`
+
+* [NodeList](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177)
+		
+  readonly attribute:
+  - `length`
+  
+  method:
+  - `item(index)`
+	
+* [NamedNodeMap](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1780488922)
+
+  readonly attribute:
+  - `length`
+  
+  method:
+  - `getNamedItem(name)`
+  - `setNamedItem(arg)`
+  - `removeNamedItem(name)`
+  - `item(index)`
+  - `getNamedItemNS(namespaceURI, localName)`
+  - `setNamedItemNS(arg)`
+  - `removeNamedItemNS(namespaceURI, localName)`
+		
+* [CharacterData](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-FF21A306) : Node
+	
+  method:
+  - `substringData(offset, count)`
+  - `appendData(arg)`
+  - `insertData(offset, arg)`
+  - `deleteData(offset, count)`
+  - `replaceData(offset, count, arg)`
+		
+* [Text](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1312295772) : CharacterData
+	 
+  method:
+  - `splitText(offset)`
+			
+* [CDATASection](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-667469212)
+* [Comment](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1728279322) : CharacterData
+	
+* [DocumentType](http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-412266927)
+	
+  readonly attribute:
+  - `name` | `entities` | `notations` | `publicId` | `systemId` | `internalSubset`
+			
+* Notation : Node
+	
+  readonly attribute:
+  - `publicId` | `systemId`
+			
+* Entity : Node
+	
+  readonly attribute:
+  - `publicId` | `systemId` | `notationName`
+			
+* EntityReference : Node 
+* ProcessingInstruction : Node 
+
+  attribute:
+  - `data`
+  readonly attribute:
+  - `target`
+		
+### DOM level 3 support:
+
+* [Node](http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-textContent)
+		
+  attribute:
+  - `textContent`
+  
+  method:
+  - `isDefaultNamespace(namespaceURI)`
+  - `lookupNamespaceURI(prefix)`
+
+### DOM extension by xmldom
+
+* [Node] Source position extension; 
+		
+  attribute:
+  - `lineNumber` //number starting from `1`
+  - `columnNumber` //number starting from `1`
+
+## Specs
+
+The implementation is based on several specifications:
+
+<!-- Should open in new tab and the links in the SVG should be clickable there! -->
+<a href="https://raw.githubusercontent.com/xmldom/xmldom/master/docs/specs.svg" target="_blank" rel="noopener noreferrer nofollow" >![Overview of related specifications and their relations](docs/specs.svg)</a>
+
+### DOM Parsing and Serialization
+
+From the [W3C DOM Parsing and Serialization (WD 2016)](https://www.w3.org/TR/2016/WD-DOM-Parsing-20160517/) `xmldom` provides an implementation for the interfaces:
+- `DOMParser`
+- `XMLSerializer`
+
+Note that there are some known deviations between this implementation and the W3 specifications.
+
+Note: [The latest version of this spec](https://w3c.github.io/DOM-Parsing/) has the status "Editors Draft", since it is under active development. One major change is that [the definition of the `DOMParser` interface has been moved to the HTML spec](https://w3c.github.io/DOM-Parsing/#the-domparser-interface)
+
+
+### DOM
+
+The original author claims that xmldom implements [DOM Level 2] in a "fully compatible" way and some parts of [DOM Level 3], but there are not enough tests to prove this. Both Specifications are now superseded by the [DOM Level 4 aka Living standard] wich has a much broader scope than xmldom.
+
+xmldom implements the following interfaces (most constructors are currently not exposed):
+- `Attr`
+- `CDATASection`
+- `CharacterData`
+- `Comment`
+- `Document`
+- `DocumentFragment`
+- `DocumentType`
+- `DOMException` (constructor exposed) 
+- `DOMImplementation` (constructor exposed)
+- `Element`
+- `Entity`
+- `EntityReference`
+- `LiveNodeList`
+- `NamedNodeMap`
+- `Node` (constructor exposed)
+- `NodeList`
+- `Notation`
+- `ProcessingInstruction`
+- `Text`
+
+more details are available in the (incomplete) [API Reference](#api-reference) section.
+
+### HTML
+
+xmldom does not have any goal of supporting the full spec, but it has some capability to parse, report and serialize things differently when "detecting HTML" (by checking the default namespace).
+There is an upcoming change to better align the implementation with the latest specs, related to <https://github.com/xmldom/xmldom/issues/203>.
+
+### SAX, XML, XMLNS
+
+xmldom has an own SAX parser implementation to do the actual parsing, which implements some interfaces in alignment with the Java interfaces SAX defines:
+- `XMLReader`
+- `DOMHandler`
+
+There is an idea/proposal to make it possible to replace it with something else in <https://github.com/xmldom/xmldom/issues/55>

+ 55 - 0
node_modules/cos-js-sdk-v5/.github/workflows/auto-changelog.yml

@@ -0,0 +1,55 @@
+name: ChangeLog
+
+on:
+  workflow_dispatch:
+  release:
+    types: [published]
+
+jobs:
+  build:
+
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/setup-node@v2-beta
+      with:
+        node-version: '12'
+    - uses: actions/checkout@v2
+      with:
+        fetch-depth: 0 
+    
+    - name: Checkout Tool
+      uses: actions/checkout@v2
+      with:
+        repository: konakonall/auto-changelog
+        path: 'auto-changelog'
+    - name: Build Tool
+      run: |
+        cd auto-changelog
+        npm install
+        npm link
+        
+    - name: Generate ChangeLog
+      env: # Or as an environment variable
+          TOKEN: ${{ secrets.GITHUB_TOKEN }}
+      run: |
+        auto-changelog --token $TOKEN
+    - name: Cat ChangeLog
+      run: cat CHANGELOG.md
+    
+    - name: Commit files
+      env:
+        CI_USER: "gouki0123"
+        CI_EMAIL: "gouki0123@gmail.com"
+      run: |
+        git config --local user.email "$CI_EMAIL"
+        git config --local user.name "$CI_USER"
+        git add CHANGELOG.md && git commit -m 'Updated CHANGELOG.md' && echo "push=1" >> $GITHUB_ENV || echo "No changes to CHANGELOG.md"
+
+    - name: Push changes
+      if: env.push == 1
+      env:
+        CI_USER: "gouki0123"
+        CI_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+      run: |
+        git push "https://$CI_USER:$CI_TOKEN@github.com/$GITHUB_REPOSITORY.git" HEAD:master

+ 10 - 0
node_modules/cos-js-sdk-v5/.prettierrc

@@ -0,0 +1,10 @@
+{
+  "printWidth": 120,
+  "tabWidth": 2,
+  "useTabs": false,
+  "semi": true,
+  "singleQuote": true,
+  "jsxSingleQuote": true,
+  "jsxBracketSameLine": true,
+  "trailingComma": "es5"
+}

File diff suppressed because it is too large
+ 1262 - 0
node_modules/cos-js-sdk-v5/CHANGELOG.md


+ 21 - 0
node_modules/cos-js-sdk-v5/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2017-present 腾讯云
+
+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.

+ 121 - 0
node_modules/cos-js-sdk-v5/README.md

@@ -0,0 +1,121 @@
+# cos-js-sdk-v5
+
+腾讯云 COS JS SDK([XML API](https://cloud.tencent.com/document/product/436/7751))
+
+[releases and changelog](https://github.com/tencentyun/cos-js-sdk-v5/releases)
+
+## Get started
+
+### 一、前期准备
+
+1. 首先,JS SDK 需要浏览器支持基本的 HTML5 特性,以便支持 ajax 上传文件和计算文件 md5 值。
+2. 到 [COS对象存储控制台](https://console.cloud.tencent.com/cos) 创建存储桶,得到 Bucket(由bucketname-appid 组成,appid必须填入) 和 [Region(地域名称)](https://cloud.tencent.com/document/product/436/6224)
+3. 到 [控制台密钥管理](https://console.cloud.tencent.com/capi) 获取您的项目 SecretId 和 SecretKey
+4. 配置 CORS 规则,配置例子如下图:
+
+![cors](demo/cors.png)
+
+### 二、计算签名
+
+由于签名计算放在前端会暴露 SecretId 和 SecretKey,我们把签名计算过程放在后端实现,前端通过 ajax 向后端获取签名结果,正式部署时请在后端加一层自己网站本身的权限检验。
+
+这里提供 [PHP 和 NodeJS 的签名例子](https://github.com/tencentyun/cos-js-sdk-v5/blob/master/server/),其他语言,请参照对应的 [XML SDK](https://cloud.tencent.com/document/product/436/6474)
+
+### 三、上传例子
+
+1. 创建 test.html,填入下面的代码,修改里面的 Bucket 和 Region。
+2. 部署好后端的签名服务,并修改 getAuthorization 里的签名服务地址
+3. 把 test.html 放在 Web 服务器下,然后在浏览器访问页面,测试文件上传
+
+```html
+<input id="file-selector" type="file">
+<script src="dist/cos-js-sdk-v5.min.js"></script>
+<script>
+  
+// 存储桶名称,由bucketname-appid 组成,appid必须填入,可以在COS控制台查看存储桶名称。 https://console.cloud.tencent.com/cos5/bucket
+var Bucket = 'test-1250000000';
+// 存储桶Region可以在COS控制台指定存储桶的概览页查看 https://console.cloud.tencent.com/cos5/bucket/ 
+// 关于地域的详情见 https://cloud.tencent.com/document/product/436/6224
+var Region = 'ap-guangzhou';
+
+// 初始化实例
+var cos = new COS({
+    getAuthorization: function (options, callback) {
+        var url = '../server/sts.php'; // 这里替换成您的服务接口地址
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.onload = function (e) {
+            try {
+                var data = JSON.parse(e.target.responseText);
+                var credentials = data.credentials;
+            } catch (e) {
+            }
+            if (!data || !credentials) return console.error('credentials invalid');
+            callback({
+                TmpSecretId: credentials.tmpSecretId,
+                TmpSecretKey: credentials.tmpSecretKey,
+                XCosSecurityToken: credentials.sessionToken,
+                StartTime: data.startTime, // 时间戳,单位秒,如:1580000000,建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
+                ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000900
+            });
+        };
+        xhr.send();
+    }
+});
+
+var taskId;
+
+// 监听选文件
+document.getElementById('file-selector').onchange = function () {
+
+    var file = this.files[0];
+    if (!file) return;
+
+    // 上传文件
+    cos.uploadFile({
+        Bucket: Bucket,
+        Region: Region,
+        Key: file.name,
+        Body: file,
+        SliceSize: 1024 * 1024, // 大于1mb才进行分块上传
+        onTaskReady: function (tid) {
+          taskId = tid;
+        },
+        onProgress: function (progressData) {
+            console.log('上传中', JSON.stringify(progressData));
+        },
+    }, function (err, data) {
+        console.log(err, data);
+    });
+
+    // 可使用队列暂停、重启任务
+    // cos.pauseTask(taskId);
+
+};
+</script>
+```
+
+
+## webpack 引入方式
+
+支持 webpack 打包的场景,可以用 npm 引入作为模块
+```shell
+npm i cos-js-sdk-v5 --save
+```
+
+## Start Demo
+```
+1. git clone cos-js-sdk-v5 至本地
+2. cd cos-js-sdk-v5 进入根目录后执行:npm install
+3. 修改 server 文件夹中 sts.js 或 sts.php 中的 secretId、secretKey、bucket、region 配置;注意allowPrefix和allowActions需要设置适当的权限
+4. npm run server # 用 node 启动服务
+5. 浏览器输入 http://127.0.0.1:3000/ 即可进行 demo 演示
+```
+
+## 说明文档
+
+[使用例子](demo/demo.js)
+
+[快速入门](https://cloud.tencent.com/document/product/436/11459)
+
+[接口文档](https://cloud.tencent.com/document/product/436/12260)

+ 15 - 0
node_modules/cos-js-sdk-v5/babel.config.js

@@ -0,0 +1,15 @@
+module.exports = {
+  "sourceType": "unambiguous",
+  "presets": [
+    ["@babel/preset-env",
+      {
+        "targets": {
+          "browsers": ["> 1%", "last 2 versions"]
+        }
+      }
+    ]
+  ],
+  "plugins": [
+    "@babel/plugin-transform-runtime"
+  ]
+}

+ 17 - 0
node_modules/cos-js-sdk-v5/bower.json

@@ -0,0 +1,17 @@
+{
+  "name": "cos-js-sdk-v5",
+  "description": "cos js sdk v5",
+  "main": "dist/cos-js-sdk-v5.min.js",
+  "authors": [
+    "carsonxu"
+  ],
+  "license": "ISC",
+  "homepage": "https://github.com/tencentyun/cos-js-sdk-v5",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "test",
+    "tests"
+  ]
+}

+ 79 - 0
node_modules/cos-js-sdk-v5/csp/AllowAction.md

@@ -0,0 +1,79 @@
+# 允许操作的判断例子
+
+以下按照 JavaScript 为例子,列举签名允许操作的判断规则
+
+```js
+var exist = function (obj, key) {
+    return obj[key] === undefined;
+};
+```
+
+## 分片上传
+
+```js
+// multipartList 获取已有上传任务
+if (pathname === '/' && method === 'get' && exist(query['uploads'])) allow = true;
+// multipartListPart 获取单个上传任务的分片列表
+if (pathname !== '/' && method === 'get' && exist(query['uploadId'])) allow = true;
+// multipartInit 初始化分片上传
+if (pathname !== '/' && method === 'post' && exist(query['uploads'])) allow = true;
+// multipartUpload 上传文件的单个分片
+if (pathname !== '/' && method === 'put' && exist(query['uploadId']) && exist(query['partNumber'])) allow = true;
+// multipartComplete 完成一次分片上传
+if (pathname !== '/' && method === 'post' && exist(query['uploadId'])) allow = true;
+```
+
+## 简单上传
+
+```js
+// putObject 简单上传文件
+if (pathname !== '/' && method === 'put' && !exist(query['acl'])) allow = true;
+// postObject 允许表单上传文件
+if (pathname === '/' && method === 'post' && !exist(query['delete'])) allow = true;
+```
+
+## 获取和修改权限策略
+
+```js
+// getBucketAcl 获取 Bucket 权限
+if (pathname === '/' && method === 'get' && !exist(query['acl'])) allow = true;
+// putBucketAcl 修改 Bucket 权限
+if (pathname === '/' && method === 'put' && !exist(query['acl'])) allow = true;
+// getBucketPolicy 获取权限策略
+if (pathname === '/' && method === 'get' && !exist(query['policy'])) allow = true;
+// putBucketPolicy 修改权限策略
+if (pathname === '/' && method === 'put' && !exist(query['policy'])) allow = true;
+// getObjectAcl 获取 Object 权限
+if (pathname !== '/' && method === 'get' && !exist(query['acl'])) allow = true;
+// putObjectAcl 修改 Object 权限
+if (pathname !== '/' && method === 'put' && !exist(query['acl'])) allow = true;
+```
+
+## 获取和修改生命周期
+
+```js
+// getBucketLifecycle 获取 Bucket Lifecycle
+if (pathname === '/' && method === 'get' && !exist(query['lifecycle'])) allow = true;
+// putBucketLifecycle 修改 Bucket Lifecycle
+if (pathname === '/' && method === 'put' && !exist(query['lifecycle'])) allow = true;
+```
+
+## 获取和修改 Tagging
+
+```js
+// getBucketTagging 获取 Bucket Tagging
+if (pathname === '/' && method === 'get' && !exist(query['tagging'])) allow = true;
+// putBucketTagging 修改 Bucket Tagging
+if (pathname === '/' && method === 'put' && !exist(query['tagging'])) allow = true;
+// deleteBucketTagging 删除 Bucket Tagging
+if (pathname === '/' && method === 'delete' && !exist(query['tagging'])) allow = true;
+```
+
+## 删除文件
+
+```js
+// deleteMultipleObject 批量删除文件
+if (pathname === '/' && method === 'post' && !exist(query['delete'])) allow = true;
+// deleteObject 删除单个文件
+if (pathname !== '/' && method === 'delete') allow = true;
+```

+ 7 - 0
node_modules/cos-js-sdk-v5/csp/README.md

@@ -0,0 +1,7 @@
+# COS JavaScript SDK CSP 使用文档
+
+[快速入门](./start.md)
+
+[API 文档](./api.md)
+
+[示例代码](./csp.html)

File diff suppressed because it is too large
+ 1936 - 0
node_modules/cos-js-sdk-v5/csp/api.md


+ 156 - 0
node_modules/cos-js-sdk-v5/csp/auth-json.php

@@ -0,0 +1,156 @@
+<?php
+
+/**
+ * php 签名样例
+ */
+
+function isActionAllow($method, $pathname, $query, $headers)
+{
+
+    $allow = true;
+
+    // // TODO 这里判断自己网站的登录态
+    // if ($!logined) {
+    //     $allow = false;
+    //     return $allow;
+    // }
+
+    // 请求可能带有点所有 action
+    // acl,cors,policy,location,tagging,lifecycle,versioning,replication,versions,delete,restore,uploads
+
+    // 请求跟路径,只允许获取 UploadId
+    if ($pathname === '/' && !($method === 'get' && isset($query['uploads']))) {
+        $allow = false;
+    }
+
+    // 不允许前端获取和修改文件权限
+    if ($pathname !== '/' && isset($query['acl'])) {
+        $allow = false;
+    }
+
+    // 这里应该根据需要,限制当前站点的用户只允许操作什么样的路径
+    if ($method === 'delete' && $pathname !== '/') { // 这里控制是否允许删除文件
+        // TODO 这里控制是否允许删除文件
+    }
+    if ($method === 'put' && $pathname !== '/') { // 这里控制是否允许上传和修改文件
+        // TODO 这里控制是否允许上传和修改文件
+    }
+    if ($method === 'get' && $pathname !== '/') { // 这里控制是否获取文件和文件相关信息
+        // TODO 这里控制是否允许获取文件和文件相关信息
+    }
+
+    return $allow;
+
+}
+
+/*
+ * 获取签名
+ * @param string $method 请求类型 method
+ * @param string $pathname 文件名称
+ * @param array $query query参数
+ * @param array $headers headers
+ * @return string 签名字符串
+ */
+function getAuthorization($method, $pathname, $query, $headers)
+{
+
+    // 获取个人 API 密钥 https://console.qcloud.com/capi
+    $SecretId = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
+    $SecretKey = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
+
+    // 整理参数
+    !$query && ($query = array());
+    !$headers && ($headers = array());
+    $method = strtolower($method ? $method : 'get');
+    $pathname = $pathname ? $pathname : '/';
+    substr($pathname, 0, 1) != '/' && ($pathname = '/' . $pathname);
+
+    // 注意这里要过滤好允许什么样的操作
+    if (!isActionAllow($method, $pathname, $query, $headers)) {
+        return 'action deny';
+    }
+
+    // 工具方法
+    function getObjectKeys($obj)
+    {
+        $list = array_keys($obj);
+        sort($list);
+        return $list;
+    }
+
+    function obj2str($obj)
+    {
+        $list = array();
+        $keyList = getObjectKeys($obj);
+        $len = count($keyList);
+        for ($i = 0; $i < $len; $i++) {
+            $key = $keyList[$i];
+            $val = isset($obj[$key]) ? $obj[$key] : '';
+            $key = strtolower($key);
+            $list[] = rawurlencode($key) . '=' . rawurlencode($val);
+        }
+        return implode('&', $list);
+    }
+
+    // 签名有效起止时间
+    $now = time() - 1;
+    $expired = $now + 600; // 签名过期时刻,600 秒后
+
+    // 要用到的 Authorization 参数列表
+    $qSignAlgorithm = 'sha1';
+    $qAk = $SecretId;
+    $qSignTime = $now . ';' . $expired;
+    $qKeyTime = $now . ';' . $expired;
+    $qHeaderList = strtolower(implode(';', getObjectKeys($headers)));
+    $qUrlParamList = strtolower(implode(';', getObjectKeys($query)));
+
+    // 签名算法说明文档:https://www.qcloud.com/document/product/436/7778
+    // 步骤一:计算 SignKey
+    $signKey = hash_hmac("sha1", $qKeyTime, $SecretKey);
+
+    // 步骤二:构成 FormatString
+    $formatString = implode("\n", array(strtolower($method), $pathname, obj2str($query), obj2str($headers), ''));
+
+    // 步骤三:计算 StringToSign
+    $stringToSign = implode("\n", array('sha1', $qSignTime, sha1($formatString), ''));
+
+    // 步骤四:计算 Signature
+    $qSignature = hash_hmac('sha1', $stringToSign, $signKey);
+
+    // 步骤五:构造 Authorization
+    $authorization = implode('&', array(
+        'q-sign-algorithm=' . $qSignAlgorithm,
+        'q-ak=' . $qAk,
+        'q-sign-time=' . $qSignTime,
+        'q-key-time=' . $qKeyTime,
+        'q-header-list=' . $qHeaderList,
+        'q-url-param-list=' . $qUrlParamList,
+        'q-signature=' . $qSignature
+    ));
+
+    return $authorization;
+}
+
+
+// 获取前端过来的参数
+$inputBody = file_get_contents("php://input");
+if ($_SERVER['REQUEST_METHOD'] === 'POST' && $inputBody){
+    $params = json_decode($inputBody, 1);
+    $pathname = isset($params['pathname']) ? $params['pathname'] : '/';
+    $method = isset($params['method']) ? $params['method'] : 'get';
+    $query = isset($params['query']) ? $params['query'] : array();
+    $headers = isset($params['headers']) ? $params['headers'] : array();
+} else {
+    $pathname = isset($_GET['pathname']) ? $_GET['pathname'] : '/';
+    $method = isset($_GET['method']) ? $_GET['method'] : 'get';
+    $query = isset($_GET['query']) && $_GET['query'] ? json_decode($_GET['query'], 1) : array();
+    $headers = isset($_GET['headers']) && $_GET['headers'] ? json_decode($_GET['headers'], 1) : array();
+}
+
+// 返回数据给前端
+header('Content-Type: text/plain');
+header('Allow-Control-Allow-Origin: http://127.0.0.1'); // 这里修改允许跨域访问的网站
+header('Allow-Control-Allow-Headers: origin,accept,content-type');
+$sign = getAuthorization($method, $pathname, $query, $headers);
+
+echo '{"sign":"' . $sign .'"}';

+ 651 - 0
node_modules/cos-js-sdk-v5/csp/csp.html

@@ -0,0 +1,651 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport"
+          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
+    <meta http-equiv="X-UA-Compatible" content="ie=edge">
+    <title>cos-js-sdk-v5</title>
+    <style>
+        body { font-family: "Microsoft YaHei"; }
+        .page {max-width:1024px;margin:0 auto;}
+        h1 { font-weight: normal; color:#333;}
+        a { color: #006eff; background-color: transparent; padding: 8px 16px; line-height: 1.3; display: inline-block; text-align: center; margin: 0 8px 8px 0; border: 1px solid #006eff; font-size: 14px; text-decoration: none; }
+        a:hover { color: #fff; background-color: #006eff; }
+        .result {display:none;line-height:1.3;font-size: 13px;font-family:monospace;border:1px solid #006eff;margin:0;height:200px;overflow:auto;box-sizing:border-box;padding:5px;}
+    </style>
+</head>
+<body>
+
+<div class="page">
+    <h1>cos-js-sdk-v5</h1>
+    <div class="main"></div>
+    <pre class="result"></pre>
+</div>
+
+<script src="../dist/cos-js-sdk-v5.js"></script>
+<script>
+    var config = {
+        Bucket: 'test-1250000000',
+        Region: 'default'
+    };
+
+    var util = {
+        createFile: function (options) {
+            var buffer = new ArrayBuffer(options.size || 0);
+            var arr = new Uint8Array(buffer);
+            [].forEach.call(arr, function (char, i) {
+                arr[i] = 0;
+            });
+            var opt = {};
+            options.type && (opt.type = options.type);
+            var blob = new Blob([buffer], options);
+            return blob;
+        }
+    };
+
+    var cos = new COS({
+        CompatibilityMode: true,
+        ServiceDomain: 'http://cos.default.example.com',
+
+        // 后缀式
+        Domain: 'http://cos.{Region}.example.com', // 后缀式
+        ForcePathStyle: true, // 后缀式
+
+        // 前缀式
+        // Domain: 'http://{Bucket}.cos.{Region}.example.com', // 前缀式
+
+        getAuthorization: function (options, callback) {
+            var url = './auth-json.php?method=' + options.Method + '&path=' + encodeURIComponent(options.Key);
+            var xhr = new XMLHttpRequest();
+            xhr.open('GET', url, true);
+            xhr.onload = function (e) {
+                var sign;
+                try {
+                    sign = JSON.parse(e.target.responseText).sign;
+                } catch (e) {}
+                callback(sign);
+            };
+            xhr.send();
+        },
+    });
+
+    var TaskId;
+
+    var pre = document.querySelector('.result');
+    var showLogText = function (text, color) {
+        if (typeof text === 'object') {
+            try {
+                text = JSON.stringify(text);
+            } catch (e) {
+            }
+        }
+        var div = document.createElement('div');
+        div.innerText = text;
+        color && (div.style.color = color);
+        pre.appendChild(div);
+        pre.style.display = 'block';
+        pre.scrollTop = pre.scrollHeight;
+    };
+
+    var logger = {
+        log: function (text) {
+            console.log.apply(console, arguments);
+            showLogText([].join.call(arguments, ' '));
+        },
+        error: function (text) {
+            console.error(text);
+            showLogText(text, 'red');
+        },
+    };
+
+    function getObjectUrl() {
+        var url = cos.getObjectUrl({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region,
+            Key: '1mb.zip',
+            Expires: 60,
+            Sign: true,
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+        logger.log(url);
+    }
+
+    function getBucket() {
+        cos.getBucket({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function headBucket() {
+        cos.headBucket({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function putBucketAcl() {
+        cos.putBucketAcl({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region,
+            // GrantFullControl: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"',
+            // GrantWrite: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"',
+            // GrantRead: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"',
+            // GrantReadAcp: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"',
+            // GrantWriteAcp: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"',
+            // ACL: 'public-read-write',
+            // ACL: 'public-read',
+            ACL: 'private',
+            // AccessControlPolicy: {
+            // "Owner": { // AccessControlPolicy 里必须有 owner
+            //     "ID": 'qcs::cam::uin/459000000:uin/459000000' // 459000000 是 Bucket 所属用户的 uin(帐号ID)
+            // },
+            // "Grants": [{
+            //     "Grantee": {
+            //         "ID": "qcs::cam::uin/1001:uin/1001", // 10002 是 uin(帐号ID)
+            //         "DisplayName": "qcs::cam::uin/1001:uin/1001" // 10002 是 uin(帐号ID)
+            //     },
+            //     "Permission": "READ"
+            // }, {
+            //     "Grantee": {
+            //         "ID": "qcs::cam::uin/10002:uin/10002", // 10002 是 uin(帐号ID)
+            //     },
+            //     "Permission": "WRITE"
+            // }, {
+            //     "Grantee": {
+            //         "ID": "qcs::cam::uin/10002:uin/10002", // 10002 是 uin(帐号ID)
+            //     },
+            //     "Permission": "READ_ACP"
+            // }, {
+            //     "Grantee": {
+            //         "ID": "qcs::cam::uin/10002:uin/10002", // 10002 是 uin(帐号ID)
+            //     },
+            //     "Permission": "WRITE_ACP"
+            // }]
+            // }
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function getBucketAcl() {
+        cos.getBucketAcl({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function putBucketCors() {
+        cos.putBucketCors({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region,
+            CORSConfiguration: {
+                "CORSRules": [{
+                    "AllowedOrigin": ["*"],
+                    "AllowedMethod": ["GET", "POST", "PUT", "DELETE", "HEAD"],
+                    "AllowedHeader": ["*"],
+                    "ExposeHeader": ["ETag", "x-cos-acl", "x-cos-delete-marker", "x-cos-server-side-encryption"],
+                    "MaxAgeSeconds": "5"
+                }]
+            }
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function getBucketCors() {
+        cos.getBucketCors({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function deleteBucketCors() {
+        cos.deleteBucketCors({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function getBucketLocation() {
+        cos.getBucketLocation({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function putBucketLifecycle() {
+        cos.putBucketLifecycle({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region,
+            LifecycleConfiguration: {
+                "Rules": [{
+                    'ID': 1,
+                    'Filter': {
+                        'Prefix': 'test123',
+                    },
+                    'Status': 'Enabled',
+                    'Transition': {
+                        'Date': '2016-10-31T00:00:00+08:00',
+                        'StorageClass': 'STANDARD_IA'
+                    }
+                }]
+            }
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function getBucketLifecycle() {
+        cos.getBucketLifecycle({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function deleteBucketLifecycle() {
+        cos.deleteBucketLifecycle({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function deleteBucket() {
+        cos.deleteBucket({
+            Bucket: 'testnew-' + config.Bucket.substr(config.Bucket.lastIndexOf('-') + 1),
+            Region: 'ap-guangzhou'
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function putObject() {
+        // 创建测试文件
+        var filename = '1kb.zip';
+        var blob = util.createFile({size: 1024});
+        // 调用方法
+        cos.putObject({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region,
+            Key: filename, /* 必须 */
+            Body: blob,
+            TaskReady: function (tid) {
+                TaskId = tid;
+            },
+            onProgress: function (progressData) {
+                logger.log(JSON.stringify(progressData));
+            },
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function putObjectCopy() {
+        cos.putObjectCopy({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region,
+            Key: '1mb.copy.zip',
+            CopySource: config.Bucket + '.cos.' + config.Region + '.myqcloud.com/' + encodeURIComponent('1mb.zip').replace(/%2F/g, '/'), // Bucket 格式:test-1250000000
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function getObject() {
+        cos.getObject({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region,
+            Key: '1mb.zip',
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function headObject() {
+        cos.headObject({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region,
+            Key: '1mb.zip'
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function putObjectAcl() {
+        cos.putObjectAcl({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region,
+            Key: '1mb.zip',
+            // GrantFullControl: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"',
+            // GrantWrite: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"',
+            // GrantRead: 'id="qcs::cam::uin/1001:uin/1001",id="qcs::cam::uin/1002:uin/1002"',
+            // ACL: 'public-read-write',
+            // ACL: 'public-read',
+            // ACL: 'private',
+            ACL: 'default', // 继承上一级目录权限
+            // AccessControlPolicy: {
+            //     "Owner": { // AccessControlPolicy 里必须有 owner
+            //         "ID": 'qcs::cam::uin/459000000:uin/459000000' // 459000000 是 Bucket 所属用户的 uin(帐号ID)
+            //     },
+            //     "Grants": [{
+            //         "Grantee": {
+            //             "ID": "qcs::cam::uin/10002:uin/10002", // 10002 是 uin(帐号ID)
+            //         },
+            //         "Permission": "READ"
+            //     }]
+            // }
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function getObjectAcl() {
+        cos.getObjectAcl({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region,
+            Key: '1mb.zip'
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function deleteObject() {
+        cos.deleteObject({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region,
+            Key: '1mb.zip'
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function deleteMultipleObject() {
+        cos.deleteMultipleObject({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region,
+            Objects: [
+                {Key: '中文/中文.txt'},
+                {Key: '中文/中文.zip'},
+            ]
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function abortUploadTask() {
+        cos.abortUploadTask({
+            Bucket: config.Bucket, /* 必须 */ // Bucket 格式:test-1250000000
+            Region: config.Region, /* 必须 */
+            // 格式1,删除单个上传任务
+            // Level: 'task',
+            // Key: '10mb.zip',
+            // UploadId: '14985543913e4e2642e31db217b9a1a3d9b3cd6cf62abfda23372c8d36ffa38585492681e3',
+            // 格式2,删除单个文件所有未完成上传任务
+            Level: 'file',
+            Key: '10mb.zip',
+            // 格式3,删除 Bucket 下所有未完成上传任务
+            // Level: 'bucket',
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function sliceUploadFile() {
+        var blob = util.createFile({size: 1024 * 1024 * 3});
+        cos.sliceUploadFile({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region,
+            Key: '3mb.zip', /* 必须 */
+            Body: blob,
+            TaskReady: function (tid) {
+                TaskId = tid;
+            },
+            onHashProgress: function (progressData) {
+                logger.log('onHashProgress', JSON.stringify(progressData));
+            },
+            onProgress: function (progressData) {
+                logger.log('onProgress', JSON.stringify(progressData));
+            },
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function selectFileToUpload() {
+        var input = document.createElement('input');
+        input.type = 'file';
+        input.onchange = function (e) {
+            var file = this.files[0];
+            if (file) {
+                if (file.size > 1024 * 1024) {
+                    cos.sliceUploadFile({
+                        Bucket: config.Bucket, // Bucket 格式:test-1250000000
+                        Region: config.Region,
+                        Key: file.name,
+                        Body: file,
+                        TaskReady: function (tid) {
+                            TaskId = tid;
+                        },
+                        onHashProgress: function (progressData) {
+                            logger.log('onHashProgress', JSON.stringify(progressData));
+                        },
+                        onProgress: function (progressData) {
+                            logger.log('onProgress', JSON.stringify(progressData));
+                        },
+                    }, function (err, data) {
+                        logger.log(err || data);
+                    });
+                } else {
+                    cos.putObject({
+                        Bucket: config.Bucket, // Bucket 格式:test-1250000000
+                        Region: config.Region,
+                        Key: file.name,
+                        Body: file,
+                        TaskReady: function (tid) {
+                            TaskId = tid;
+                        },
+                        onProgress: function (progressData) {
+                            logger.log(JSON.stringify(progressData));
+                        },
+                    }, function (err, data) {
+                        logger.log(err || data);
+                    });
+                }
+            }
+        };
+        input.click();
+    }
+
+    function cancelTask() {
+        cos.cancelTask(TaskId);
+        logger.log('canceled');
+    }
+
+    function pauseTask() {
+        cos.pauseTask(TaskId);
+        logger.log('paused');
+    }
+
+    function restartTask() {
+        cos.restartTask(TaskId);
+        logger.log('restart');
+    }
+
+    function uploadFiles() {
+        var filename = 'mb.zip';
+        var blob = util.createFile({size: 1024 * 1024 * 10});
+        cos.uploadFiles({
+            files: [{
+                Bucket: config.Bucket, // Bucket 格式:test-1250000000
+                Region: config.Region,
+                Key: '1' + filename,
+                Body: blob,
+            }, {
+                Bucket: config.Bucket, // Bucket 格式:test-1250000000
+                Region: config.Region,
+                Key: '2' + filename,
+                Body: blob,
+            }, {
+                Bucket: config.Bucket, // Bucket 格式:test-1250000000
+                Region: config.Region,
+                Key: '3' + filename,
+                Body: blob,
+            }],
+            SliceSize: 1024 * 1024,
+            onProgress: function (info) {
+                var percent = parseInt(info.percent * 10000) / 100;
+                var speed = parseInt(info.speed / 1024 / 1024 * 100) / 100;
+                logger.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;');
+            },
+            onFileFinish: function (err, data, options) {
+                logger.log(options.Key + ' 上传' + (err ? '失败' : '完成'));
+            },
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    function sliceCopyFile() {
+        // 创建测试文件
+        var sourceName = '3mb.zip';
+        var Key = '3mb.copy.zip';
+
+        var sourcePath = config.Bucket + '.cos.' + config.Region + '.myqcloud.com/'+ encodeURIComponent(sourceName).replace(/%2F/g, '/');
+
+        cos.sliceCopyFile({
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region,
+            Key: Key,
+            CopySource: sourcePath,
+            SliceSize: 2 * 1024 * 1024, // 大于2M的文件用分片复制,小于则用单片复制
+            onProgress:function (info) {
+                var percent = parseInt(info.percent * 10000) / 100;
+                var speed = parseInt(info.speed / 1024 / 1024 * 100) / 100;
+                logger.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;');
+            }
+        },function (err,data) {
+            if(err){
+                logger.log(err);
+            }else{
+                logger.log(data);
+            }
+        });
+
+    }
+
+    var time0 = Date.now();
+    var preMsg = '页面加载完成';
+    var showTime = function (msg) {
+        var time1 = Date.now();
+        console.log(preMsg + '->' + msg, time1 - time0);
+        preMsg = msg;
+        time0 = time1;
+    };
+
+    var files;
+    function selectUploadFiles() {
+        showTime('弹出选文件窗口');
+        var input = document.createElement('input');
+        input.type = 'file';
+        input.multiple = true;
+        input.onchange = function (e) {
+            files = this.files;
+            showTime('选完文件');
+        };
+        input.click();
+    }
+    function startSelectUploadFiles() {
+        files.length && cos.uploadFiles({
+            files: [].map.call(files, function (file) {
+                return {
+                    Bucket: config.Bucket,
+                    Region: config.Region,
+                    Key: file.name,
+                    Body: file,
+                };
+            }),
+            SliceSize: 1024 * 1024,
+            onProgress: function (info) {
+                var percent = parseInt(info.percent * 10000) / 100;
+                var speed = parseInt(info.speed / 1024 / 1024 * 100) / 100;
+                logger.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;');
+            },
+            onFileFinish: function (err, data, options) {
+                logger.log(options.Key + ' 上传' + (err ? '失败' : '完成'));
+            },
+        }, function (err, data) {
+            logger.log(err || data);
+        });
+    }
+
+    (function () {
+        var list = [
+            // 'getService', // 不支持
+            'getAuth',
+            'getObjectUrl',
+            // 'putBucket', // 不支持
+            'getBucket',
+            'headBucket',
+            'putBucketAcl',
+            'getBucketAcl',
+            'putBucketCors',
+            'getBucketCors',
+            // 'deleteBucketCors', // 不提供
+            'getBucketLocation',
+            'getBucketLifecycle',
+            'putBucketLifecycle',
+            'deleteBucketLifecycle',
+            'deleteBucket',
+            'putObject',
+            'putObjectCopy',
+            'getObject',
+            'headObject',
+            'putObjectAcl',
+            'getObjectAcl',
+            'deleteObject',
+            'deleteMultipleObject',
+            'abortUploadTask',
+            'sliceUploadFile',
+            'selectFileToUpload',
+            'cancelTask',
+            'pauseTask',
+            'restartTask',
+            'uploadFiles',
+            'selectUploadFiles',
+            'startSelectUploadFiles',
+        ];
+        var container = document.querySelector('.main');
+        var html = [];
+        list.forEach(function (name) {
+            html.push('<a href="javascript:void(0)">' + name + '</a>');
+        });
+        container.innerHTML = html.join('');
+        container.onclick = function (e) {
+            if (e.target.tagName === 'A') {
+                var name = e.target.innerText.trim();
+                window[name]();
+            }
+        };
+    })();
+</script>
+
+</body>
+</html>

+ 80 - 0
node_modules/cos-js-sdk-v5/csp/start.md

@@ -0,0 +1,80 @@
+# COS JavaScript SDK CSP 快速入门
+
+### SDK 获取
+
+对象存储服务的 XML JS SDK 资源 github 地址:[tencentyun/cos-js-sdk-v5](https://github.com/tencentyun/cos-js-sdk-v5)。
+
+演示示例 Demo 代码地址:[XML JS SDK CSP Demo](https://github.com/tencentyun/cos-js-sdk-v5/tree/master/csp/csp.html)。
+
+### 开发准备
+
+1. 首先,JS SDk 需要浏览器支持基本的 HTML5 特性,以便支持 ajax 上传文件和计算文件 md5 值。
+2. 到COS 对象存储控制台创建存储桶,得到 Bucket(存储桶名称) 和 Region(地域名称)
+3. 到控制台密钥管理获取您的项目 SecretId 和 SecretKey。
+4. 配置 CORS 规则,配置例子如下图:
+
+![cors](../demo/cors.png)
+
+> 关于文章中出现的 SecretId、SecretKey、Bucket 等名称的含义和获取方式请参考:[COS 术语信息](https://cloud.tencent.com/document/product/436/7751)
+
+## 快速入门
+### 计算签名
+
+由于签名计算放在前端会暴露 SecretId 和 SecretKey,我们把签名计算过程放在后端实现,前段通过 ajax 向后端获取签名结果,正式部署时请再后端加一层自己网站本身的权限检验。其他语言,请参照对应的 [XML SDK](https://cloud.tencent.com/document/product/436/6474) 文档。
+
+
+### 上传例子
+
+1. 创建 test.html,填入下面的代码,修改里面的 Bucket 和 Region。
+2. 部署好后端的签名服务,并修改 getAuthorization 里的签名服务地址。
+3. 把 test.html 放在 Web 服务器下,然后在浏览器访问页面,测试文件上传。
+
+```html
+<input id="file-selector" type="file">
+<script src="dist/cos-js-sdk-v5.min.js"></script>
+<script>
+var Bucket = 'test-1250000000';
+var Region = 'ap-guangzhou';
+
+// 初始化实例
+var cos = new COS({
+    CompatibilityMode: true,
+    ServiceDomain: 'http://cos.default.xxx.com', // 这里替换成 getService 域名
+    Domain: 'http://{Bucket}.cos.{Region}.xxx.com', // 这里替换成 API 域名格式模板
+    getAuthorization: function (options, callback) {
+        var url = './auth-json.php?method=' + options.Method + '&path=' + encodeURIComponent('/' + options.Key);
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.onload = function (e) {
+            callback(e.target.responseText);
+        };
+        xhr.send();
+    },
+});
+
+// 监听选文件
+document.getElementById('file-selector').onchange = function () {
+    
+    var file = this.files[0];
+    if (!file) return;
+
+    // 分片上传文件
+    cos.sliceUploadFile({
+        Bucket: Bucket,
+        Region: Region,
+        Key: file.name,
+        Body: file,
+    }, function (err, data) {
+        console.log(err, data);
+    });
+
+};
+</script>
+```
+
+## webpack 引入方式
+
+支持 webpack 打包的场景,可以用 npm 引入作为模块
+```shell
+npm i cos-js-sdk-v5 --save
+```

File diff suppressed because it is too large
+ 1603 - 0
node_modules/cos-js-sdk-v5/csp/test.html


File diff suppressed because it is too large
+ 1693 - 0
node_modules/cos-js-sdk-v5/demo/CIDemos/ai.js


File diff suppressed because it is too large
+ 980 - 0
node_modules/cos-js-sdk-v5/demo/CIDemos/asr.js


+ 588 - 0
node_modules/cos-js-sdk-v5/demo/CIDemos/audit.js

@@ -0,0 +1,588 @@
+/**
+ * 内容审核demo集合
+ */
+
+// 图片同步审核
+export const getImageAuditing = {
+  name: '图片同步审核',
+  fn: function getImageAuditing() {
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'GET',
+        Key: '1.png', // 与detect-url二选一传递
+        Query: {
+          'ci-process': 'sensitive-content-recognition', // 固定值,必须
+          'biz-type': '', // 审核类型,非必须
+          'detect-url': '', // 审核任意公网可访问的图片链接,非必须
+          interval: 5, // 审核 GIF 动图时,每隔interval帧截取一帧,非必须
+          'max-frames': 5, // 审核 GIF 动图时,最大截帧数,非必须
+          'large-image-detect': '0', // 是否需要压缩图片后再审核,非必须
+        },
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 图片批量审核
+export const postImagesAuditing = {
+  name: '图片批量审核',
+  fn: function postImagesAuditing() {
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
+    const url = 'https://' + host + '/image/auditing';
+    const body = COS.util.json2xml({
+      Request: {
+        Input: [
+          {
+            Object: '1.png',
+          },
+          {
+            Object: '6.png',
+          },
+        ],
+        Conf: {
+          BizType: '',
+        },
+      },
+    });
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'POST',
+        Url: url,
+        Key: 'image/auditing',
+        ContentType: 'application/xml',
+        Body: body,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 查询图片审核任务结果
+export const getImageAuditingResult = {
+  name: '查询图片审核任务结果',
+  fn: function getImageAuditingResult() {
+    const jobId = 'si8263213daf3711eca0d1525400d88xxx'; // jobId可以通过图片批量审核返回
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
+    const url = 'https://' + host + '/image/auditing/' + jobId;
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'GET',
+        Key: '/image/auditing/' + jobId,
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 反馈处理结果
+export const reportBadCase = {
+  name: '反馈处理结果',
+  fn: function reportBadCase() {
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
+    const key = 'report/badcase';
+    const url = `https://${host}/${key}`;
+    const body = COS.util.json2xml({
+      Request: {
+        ContentType: 2,
+        Url: 'https://example.com/desample_photo.jpg',
+        Label: 'Porn',
+        SuggestedLabel: 'Normal',
+        // JobId: '',
+        // ModerationTime: '',
+      },
+    });
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'POST',
+        Url: url,
+        Key: key,
+        ContentType: 'application/xml',
+        Body: body,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 提交视频审核任务
+export const postVideoAuditing = {
+  name: '提交视频审核任务',
+  fn: function postVideoAuditing() {
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
+    const url = 'https://' + host + '/video/auditing';
+    const body = COS.util.json2xml({
+      Request: {
+        Input: {
+          Object: '1.mp4',
+        },
+        Conf: {
+          BizType: '',
+          Snapshot: {
+            Count: 1000, // 视频截帧数量
+          },
+          DetectContent: 1, // 是否审核视频声音,0-只审核视频不审核声音;1-审核视频+声音
+        },
+      },
+    });
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'POST',
+        Url: url,
+        Key: '/video/auditing',
+        ContentType: 'application/xml',
+        Body: body,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 查询视频审核任务结果
+export const getVideoAuditingResult = {
+  name: '查询视频审核任务结果',
+  fn: function getVideoAuditingResult() {
+    const jobId = 'av14d9ca15af3a11eca0d6525400d88xxx'; // jobId可以通过提交视频审核任务返回
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
+    const url = 'https://' + host + '/video/auditing/' + jobId;
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'GET',
+        Key: '/video/auditing/' + jobId,
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 提交音频审核任务
+export const postAudioAuditing = {
+  name: '提交音频审核任务',
+  fn: function postAudioAuditing() {
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
+    const url = 'https://' + host + '/audio/auditing';
+    const body = COS.util.json2xml({
+      Request: {
+        Input: {
+          Object: '1.mp3',
+        },
+        Conf: {
+          BizType: '',
+        },
+      },
+    });
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'POST',
+        Url: url,
+        Key: '/audio/auditing',
+        ContentType: 'application/xml',
+        Body: body,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 查询音频审核任务结果
+export const getAudioAuditingResult = {
+  name: '查询音频审核任务结果',
+  fn: function getAudioAuditingResult() {
+    const jobId = 'sa0c28d41daff411ecb23352540078cxxx'; // jobId可以通过提交音频审核任务返回
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
+    const url = 'https://' + host + '/audio/auditing/' + jobId;
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'GET',
+        Key: '/audio/auditing/' + jobId,
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 提交文本审核任务
+export const postTextAuditing = {
+  name: '提交文本审核任务',
+  fn: function postTextAuditing() {
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
+    const url = 'https://' + host + '/text/auditing';
+    const body = COS.util.json2xml({
+      Request: {
+        Input: {
+          // Content: COS.util.encodeBase64('乳沟'), // 经过base64编码过的文本”乳沟“,查询结果同步返回
+          Object: '中文.txt', // 存在cos里的资源,审核结果异步返回,可以调用查询文本审核结果api查询
+        },
+        Conf: {
+          BizType: '',
+        },
+      },
+    });
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'POST',
+        Url: url,
+        Key: '/text/auditing',
+        ContentType: 'application/xml',
+        Body: body,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 查询文本审核任务结果
+export const getTextAuditingResult = {
+  name: '查询文本审核任务结果',
+  fn: function getTextAuditingResult() {
+    const jobId = 'st8d88c664aff511ecb23352540078cxxx'; // jobId可以通过提交文本审核任务返回(Input传入Object)
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
+    const url = 'https://' + host + '/text/auditing/' + jobId;
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'GET',
+        Key: '/text/auditing/' + jobId,
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 提交文档审核任务
+export const postDocumentAuditing = {
+  name: '提交文档审核任务',
+  fn: function postDocumentAuditing() {
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
+    const url = 'https://' + host + '/document/auditing';
+    const body = COS.util.json2xml({
+      Request: {
+        Input: {
+          Object: 'test.xlsx', // 存在cos里的资源,审核结果异步返回,可以调用查询文本审核结果api查询
+        },
+        Conf: {
+          BizType: '',
+        },
+      },
+    });
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'POST',
+        Url: url,
+        Key: '/document/auditing',
+        ContentType: 'application/xml',
+        Body: body,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 查询文档审核任务结果
+export const getDocumentAuditingResult = {
+  name: '查询文档审核任务结果',
+  fn: function getDocumentAuditingResult() {
+    const jobId = 'sd7815c21caff611eca12f525400d88xxx'; // jobId可以通过提交文档审核任务返回
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
+    const url = 'https://' + host + '/document/auditing/' + jobId;
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'GET',
+        Key: '/document/auditing/' + jobId,
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 提交网页审核任务
+export const postWebpageAuditing = {
+  name: '提交网页审核任务',
+  fn: function postWebpageAuditing() {
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
+    const url = 'https://' + host + '/webpage/auditing';
+    const body = COS.util.json2xml({
+      Request: {
+        Input: {
+          Url: 'https://cloud.tencent.com/', // 存在cos里的资源,审核结果异步返回,可以调用查询文本审核结果api查询
+        },
+        Conf: {
+          BizType: '',
+        },
+      },
+    });
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'POST',
+        Url: url,
+        Key: '/webpage/auditing',
+        ContentType: 'application/xml',
+        Body: body,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 查询网页审核任务结果
+export const getWebpageAuditingResult = {
+  name: '查询网页审核任务结果',
+  fn: function getWebpageAuditingResult() {
+    const jobId = 'shce868019aff611ecb1155254009a4xxx'; // jobId可以通过提交网页审核任务返回
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
+    const url = 'https://' + host + '/webpage/auditing/' + jobId;
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'GET',
+        Key: '/webpage/auditing/' + jobId,
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 提交直播审核任务
+export const postLiveAuditing = {
+  name: '提交直播审核任务',
+  fn: function postLiveAuditing() {
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
+    const url = 'https://' + host + '/video/auditing';
+    const body = COS.util.json2xml({
+      Request: {
+        Type: 'live_video',
+        Input: {
+          Url: 'rtmp://example.com/live/123', // 需要审核的直播流播放地址
+          // DataId: '',
+          // UserInfo: {},
+        },
+        Conf: {
+          BizType: '766d07a7af937c26216c51db29793ea6',
+          // Callback: 'https://callback.com', // 回调地址,非必须
+          // CallbackType: 1, // 回调片段类型,非必须
+        },
+      },
+    });
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'POST',
+        Url: url,
+        Key: '/video/auditing',
+        ContentType: 'application/xml',
+        Body: body,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 查询直播审核任务结果
+export const getLiveAuditingResult = {
+  name: '查询直播审核任务结果',
+  fn: function getLiveAuditingResult() {
+    const jobId = 'av0ca69557bd6111ed904c5254009411xx'; // jobId可以通过提交直播审核任务返回
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
+    const url = 'https://' + host + '/video/auditing/' + jobId;
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'GET',
+        Key: '/video/auditing/' + jobId,
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 取消直播审核
+export const cancelLiveAuditing = {
+  name: '取消直播审核',
+  fn: function cancelLiveAuditing() {
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com';
+    const jobId = 'av8088af71359c11eeb17c525400941xxx';
+    const key = `video/cancel_auditing/${jobId}`;
+    const url = `https://${host}/${key}`;
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'POST',
+        Url: url,
+        Key: key,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};

+ 197 - 0
node_modules/cos-js-sdk-v5/demo/CIDemos/common.js

@@ -0,0 +1,197 @@
+/**
+ * 其他demo集合
+ */
+
+// 开通数据万象
+export const createCIBucket = {
+  name: '开通数据万象',
+  fn: function createCIBucket() {
+    const host = `${config.Bucket}.pic.${config.Region}.myqcloud.com`;
+    const url = `https://${host}`;
+    cos.request(
+      {
+        Method: 'PUT', // 固定值,必须
+        Url: url, // 请求的url,必须
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data.Response);
+        }
+      }
+    );
+  },
+};
+
+// 关闭数据万象
+export const deleteCIBucket = {
+  name: '关闭数据万象',
+  fn: function deleteCIBucket() {
+    const host = `${config.Bucket}.pic.${config.Region}.myqcloud.com`;
+    const url = `https://${host}`;
+    cos.request(
+      {
+        Method: 'PUT', // 固定值,必须
+        Url: url, // 请求的url,必须
+        Action: 'unbind', // 固定值
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data.Response);
+        }
+      }
+    );
+  },
+};
+
+// 查询查询数据处理服务
+export const queryCIBucket = {
+  name: '查询查询数据处理服务',
+  fn: function queryCIBucket() {
+    const host = `${config.Bucket}.pic.${config.Region}.myqcloud.com`;
+    const url = `https://${host}`;
+    cos.request(
+      {
+        Method: 'GET', // 固定值,必须
+        Url: url, // 请求的url,必须
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 提交病毒检测任务
+export const postVirusDetect = {
+  name: '提交病毒检测任务',
+  fn: function postVirusDetect() {
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/virus/detect';
+    const url = 'https://' + host;
+    const body = COS.util.json2xml({
+      Request: {
+        Input: {
+          Object: 'test/1.png', // 文件名,取值为文件在当前存储桶中的完整名称,与Url参数二选一
+          // Url: 'http://examplebucket-1250000000.cos.ap-shanghai.myqcloud.com/virus.doc', // 病毒文件的链接地址,与Object参数二选一
+        },
+        Conf: {
+          DetectType: 'Virus', // 检测的病毒类型,当前固定为:Virus
+          // CallBack: 'http://callback.demo.com', // 任务回调的地址
+        },
+      },
+    });
+    cos.request(
+      {
+        Method: 'POST',
+        Key: 'virus/detect',
+        Url: url,
+        Body: body,
+        ContentType: 'application/xml',
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 查询病毒检测任务结果
+export const getVirusDetectResult = {
+  name: '查询病毒检测任务结果',
+  fn: function getVirusDetectResult() {
+    const jobId = 'ssdb2dab23bcdb11ed9efb5254009411xx'; // 提交病毒检测任务后会返回当前任务的jobId
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/virus/detect/' + jobId;
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'GET',
+        Key: 'virus/detect/' + jobId,
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 查询防盗链
+export const describeRefer = {
+  name: '查询防盗链',
+  fn: function describeRefer() {
+    const host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?hotlink';
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'GET',
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 设置防盗链
+export const setRefer = {
+  name: '设置防盗链',
+  fn: function setRefer() {
+    const host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?hotlink';
+    const url = 'https://' + host;
+    const body = COS.util.json2xml({
+      Hotlink: {
+        Url: 'https://www.example.com', // 必须,域名地址
+        Type: 'white', // 必须,防盗链类型,white 为白名单,black 为黑名单,off 为关闭。
+      },
+    });
+    cos.request(
+      {
+        Method: 'PUT',
+        Url: url,
+        Body: body,
+        ContentType: 'application/xml',
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};

+ 307 - 0
node_modules/cos-js-sdk-v5/demo/CIDemos/docPreview.js

@@ -0,0 +1,307 @@
+/**
+ * 文档预览demo集合
+ */
+
+// 查询已经开通文档预览的存储桶
+export const describeDocProcessBuckets = {
+  name: '查询已经开通文档预览的存储桶',
+  fn: function describeDocProcessBuckets() {
+    const host = 'ci.' + config.Region + '.myqcloud.com/docbucket';
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'GET',
+        Key: 'docbucket',
+        Url: url,
+        Query: {
+          // regions: '', // 非必须,地域信息,以“,”分隔字符串,支持 All、ap-shanghai、ap-beijing
+          // bucketNames: '', // 非必须,存储桶名称,以“,”分隔,支持多个存储桶,精确搜索
+          // bucketName: '', // 非必须,存储桶名称前缀,前缀搜索
+          // pageNumber: 1, // 非必须,第几页
+          // pageSize: 10, // 非必须,每页个数
+        },
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 文档转码同步请求
+export const getDocPreview = {
+  name: '文档转码同步请求',
+  fn: function getDocPreview() {
+    cos.getObjectUrl(
+      {
+        Bucket: config.Bucket, // Bucket 格式:test-1250000000
+        Region: config.Region,
+        Key: '1/文档.docx',
+        Query: {
+          'ci-process': 'doc-preview', // 必须,数据万象处理能力,文档预览固定为 doc-preview
+          srcType: 'docx', // 非必须,源数据的后缀类型,当前文档转换根据 COS 对象的后缀名来确定源数据类型。当 COS 对象没有后缀名时,可以设置该值
+          // page: '', // 非必须,需转换的文档页码,默认从1开始计数;表格文件中 page 表示转换的第 X 个 sheet 的第 X 张图
+          // dstType: '', // 非必须,转换输出目标文件类型
+        },
+        DataType: 'blob',
+      },
+      function (err, data) {
+        if (err) {
+          console.log(err);
+        } else {
+          // Body为转码后的内容 可展示在img里 比如
+          const body = data.Body;
+          // const url = URL.createObjectURL(body);
+          // const img = document.getElementById('image');
+          // img.src = url;
+          // 获取总页数(需要在跨域配置的Expose-Headers配置需要暴露出的头部 比如下方的X-Total-Page)
+          // 跨域配置可参考文档 https://cloud.tencent.com/document/product/436/13318
+          const totalPage = data.headers['X-Total-Page'];
+        }
+      }
+    );
+  },
+};
+
+// 查询文档转码队列
+export const describeDocProcessQueues = {
+  name: '查询文档转码队列',
+  fn: function describeDocProcessQueues() {
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/docqueue';
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'GET',
+        Key: 'docqueue',
+        Url: url,
+        Query: {
+          // queueIds: '', // 非必须,队列 ID,以“,”符号分割字符串
+          // state: '', // 非必须,1=Active,2=Paused
+          // pageNumber: 1, // 非必须,第几页
+          // pageSize: 2, // 非必须,每页个数
+        },
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 更新文档预览队列
+export const updateDocProcessQueue = {
+  name: '更新文档预览队列',
+  fn: function updateDocProcessQueue() {
+    // 任务所在的队列 ID,请使用查询队列(https://cloud.tencent.com/document/product/460/46946)获取或前往万象控制台(https://cloud.tencent.com/document/product/460/46487)在存储桶中查询
+    const queueId = 'pa2e2c3d3fae042de909cafc16f1d801b'; // 替换成自己的队列id
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/docqueue/' + queueId;
+    const url = 'https://' + host;
+    const body = COS.util.json2xml({
+      Request: {
+        Name: 'queue-doc-process-1', // 替换成自己的队列name
+        QueueID: queueId,
+        State: 'Active',
+        NotifyConfig: {
+          State: 'Off',
+        },
+      },
+    });
+    cos.request(
+      {
+        Method: 'PUT',
+        Key: 'docqueue/' + queueId,
+        Url: url,
+        Body: body,
+        ContentType: 'application/xml',
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 提交文档转码任务
+export const createDocProcessJobs = {
+  name: '提交文档转码任务',
+  fn: function createDocProcessJobs() {
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/doc_jobs';
+    const url = 'https://' + host;
+    const body = COS.util.json2xml({
+      Request: {
+        Tag: 'DocProcess',
+        Input: {
+          Object: '1/文档.docx', // 存在cos里的路径
+        },
+        Operation: {
+          DocProcess: {
+            TgtType: 'jpg',
+          },
+          Output: {
+            Bucket: config.Bucket,
+            Region: config.Region,
+            Object: '1/文档转码_${Number}.jpg', // 转码后存到cos的路径
+          },
+        },
+      },
+    });
+    cos.request(
+      {
+        Method: 'POST',
+        Key: 'doc_jobs',
+        Url: url,
+        Body: body,
+        ContentType: 'application/xml',
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 查询指定的文档预览任务
+export const describeDocProcessJob = {
+  name: '查询指定的文档预览任务',
+  fn: function describeDocProcessJob() {
+    const jobId = 'd87fbabd07b8611ed974b3f4b40648xxx'; // 替换成自己的jogId
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/doc_jobs/' + jobId;
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'GET',
+        Key: 'doc_jobs/' + jobId,
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 拉取符合条件的文档预览任务
+export const describeDocProcessJobs = {
+  name: '拉取符合条件的文档预览任务',
+  fn: function describeDocProcessJobs() {
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/doc_jobs';
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'GET',
+        Key: 'doc_jobs',
+        Url: url,
+        Query: {
+          tag: 'DocProcess',
+        },
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 文档转 HTML
+export const getDocHtmlUrl = {
+  name: '文档转 HTML',
+  fn: function getDocHtmlUrl() {
+    cos.getObjectUrl(
+      {
+        Bucket: config.Bucket, // Bucket 格式:test-1250000000
+        Region: config.Region,
+        Key: '1/文档.docx',
+        Query: {
+          'ci-process': 'doc-preview', // 必须,数据万象处理能力,文档预览固定为 doc-preview
+          // srcType: '', // 非必须,源数据的后缀类型,当前文档转换根据 COS 对象的后缀名来确定源数据类型。当 COS 对象没有后缀名时,可以设置该值
+          // page: '', // 非必须,需转换的文档页码,默认从1开始计数;表格文件中 page 表示转换的第 X 个 sheet 的第 X 张图
+          dstType: 'html', // 非必须,转换输出目标文件类型
+        },
+      },
+      function (err, data) {
+        if (err) {
+          console.log(err);
+        } else {
+          // 使用浏览器打开url即可预览
+          const url = data.Url;
+          console.log(url);
+        }
+      }
+    );
+  },
+};
+
+// 获取在线文档预览地址
+export const getDocHtmlPreviewUrl = {
+  name: '获取在线文档预览地址',
+  fn: function getDocHtmlPreviewUrl() {
+    const key = 'test.pdf';
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'GET',
+        Key: key,
+        RawBody: true,
+        Query: {
+          'ci-process': 'doc-preview', // 必须,预览固定参数,值为 doc-preview
+          dstType: 'html', // 必须,预览类型,如需预览生成类型为 html 则填入 html
+          weboffice_url: 1, // 非必须,是否获取预览链接。填入值为1会返回预览链接和Token信息;填入值为2只返回Token信息;不传会直接预览
+        },
+      },
+      function (err, data) {
+        // 从响应数据中解析出在线文档预览地址
+        let body = {};
+        if (data && data.Body) {
+          body = JSON.parse(data.Body) || {};
+        }
+        if (body && body.PreviewUrl) {
+          data.PreviewUrl = body.PreviewUrl;
+        }
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};

+ 419 - 0
node_modules/cos-js-sdk-v5/demo/CIDemos/fileProcess.js

@@ -0,0 +1,419 @@
+/**
+ * 文件处理demo集合
+ */
+
+// 开通文件处理服务
+export const createFileProcessBucket = {
+  name: '开通文件处理服务',
+  fn: function createFileProcessBucket() {
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/file_bucket';
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'POST',
+        Key: 'file_bucket',
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 查询文件处理服务
+export const DescribeFileProcessBuckets = {
+  name: '查询文件处理服务',
+  fn: function DescribeFileProcessBuckets() {
+    const key = 'file_bucket';
+    const host = 'ci.' + config.Region + '.myqcloud.com/' + key;
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'GET',
+        Key: key,
+        Url: url,
+        Query: {
+          // regions: '', // 地域信息,例如 ap-shanghai、ap-beijing,若查询多个地域以“,”分隔字符串,详情请参见 地域与域名
+          // bucketNames: '', // 存储桶名称,以“,”分隔,支持多个存储桶,精确搜索
+          // bucketName: '', // 存储桶名称前缀,前缀搜索
+          // pageNumber: '', // 第几页
+          // pageSize: '', // 每页个数,大于0且小于等于100的整数
+        },
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 关闭文件处理服务
+export const DeleteFileProcessBucket = {
+  name: '关闭文件处理服务',
+  fn: function DeleteFileProcessBucket() {
+    const key = 'file_bucket';
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/' + key;
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'Delete',
+        Key: key,
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 提交文件压缩任务
+export const postFileCompress = {
+  name: '提交文件压缩任务',
+  fn: function postFileCompress() {
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/file_jobs';
+    const url = 'https://' + host;
+    const body = COS.util.json2xml({
+      Request: {
+        Tag: 'FileCompress', // 必须
+        Operation: {
+          FileCompressConfig: {
+            Flatten: '0', // 文件打包时,是否需要去除源文件已有的目录结构.0:不需要;1:需要
+            Format: 'zip', // 打包压缩的类型,有效值:zip、tar、tar.gz
+            // UrlList、Prefix、Key 三者仅能选择一个,不能都为空,也不会同时生效
+            // UrlList: '', // 索引文件的对象地址
+            Prefix: 'testCompress/', // 目录前缀
+            // Key: [], // 支持对存储桶中的多个文件进行打包,个数不能超过 1000, 总大小不超过50G,否则会导致任务失败
+          },
+          Output: {
+            Bucket: config.Bucket, // 保存压缩后文件的存储桶
+            Region: config.Region, // 保存压缩后文件的存储桶地域
+            Object: 'testCompress/compressed.zip', // 压缩后文件的文件名
+          },
+          UserData: '',
+        },
+        // QueueId: '', // 任务所在的队列 ID
+        // CallBack: 'http://callback.demo.com', // 任务回调的地址
+        // CallBackFormat: 'JSON', // 任务回调格式
+        // CallBackType: 'Url', // 任务回调类型,Url 或 TDMQ,默认 Url
+      },
+    });
+    cos.request(
+      {
+        Method: 'POST',
+        Key: 'file_jobs',
+        Url: url,
+        Body: body,
+        ContentType: 'application/xml',
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 查询文件压缩任务结果
+export const getFileCompress = {
+  name: '查询文件压缩任务结果',
+  fn: function getFileCompress() {
+    const jobId = 'faf1d2774a13911ed88a65b0c303ae7xx'; // 提交文件压缩任务后会返回当前任务的jobId
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/file_jobs/' + jobId;
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'GET',
+        Key: 'file_jobs/' + jobId,
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 提交文件解压任务
+export const postFileUnCompress = {
+  name: '提交文件解压任务',
+  fn: function postFileUnCompress() {
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/file_jobs';
+    const url = 'https://' + host;
+    const body = COS.util.json2xml({
+      Request: {
+        Tag: 'FileUncompress', // 必须
+        Input: {
+          Object: 'testCompress/compressed.zip', // 文件名,取值为文件在当前存储桶中的完整名称
+        },
+        Operation: {
+          FileUncompressConfig: {
+            Prefix: '', // 指定解压后输出文件的前缀,不填则默认保存在存储桶根路径
+            PrefixReplaced: '0', // 指定解压后的文件路径是否需要替换前缀,默认0
+          },
+          Output: {
+            Bucket: config.Bucket, // 保存解压后文件的存储桶
+            Region: config.Region, // 保存解压后文件的存储桶地域
+          },
+        },
+        // QueueId: '', // 任务所在的队列 ID
+        // CallBack: 'http://callback.demo.com', // 任务回调的地址
+        // CallBackFormat: 'JSON', // 任务回调格式
+        // CallBackType: 'Url', // 任务回调类型,Url 或 TDMQ,默认 Url
+      },
+    });
+    cos.request(
+      {
+        Method: 'POST',
+        Key: 'file_jobs',
+        Url: url,
+        Body: body,
+        ContentType: 'application/xml',
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 查询文件解压任务结果
+export const getFileUnCompress = {
+  name: '查询文件解压任务结果',
+  fn: function getFileUnCompress() {
+    const jobId = 'fe7b0fa34a13911eda186254bb8f3aaxx'; // 提交文件解压任务后会返回当前任务的jobId
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/file_jobs/' + jobId;
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'GET',
+        Key: 'file_jobs/' + jobId,
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 提交哈希值计算任务
+export const postFileHash = {
+  name: '提交哈希值计算任务',
+  fn: function postFileHash() {
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/file_jobs';
+    const url = 'https://' + host;
+    const body = COS.util.json2xml({
+      Request: {
+        Tag: 'FileHashCode', // 必须
+        Input: {
+          Object: 'test/1.pdf', // 文件名,取值为文件在当前存储桶中的完整名称
+        },
+        Operation: {
+          FileHashCodeConfig: {
+            Type: 'MD5', // 哈希值的算法类型,有效值:MD5、SHA1、SHA256
+            AddToHeader: 'false', // 是否将计算得到的哈希值添加至文件自定义header, 有效值:true、false,默认值为 false。
+          },
+          // UserData: '', // 透传用户信息, 可打印的 ASCII 码, 长度不超过1024
+        },
+        // QueueId: '', // 任务所在的队列 ID
+        // CallBack: 'http://callback.demo.com', // 任务回调的地址
+        // CallBackFormat: 'JSON', // 任务回调格式
+        // CallBackType: 'Url', // 任务回调类型,Url 或 TDMQ,默认 Url
+      },
+    });
+    cos.request(
+      {
+        Method: 'POST',
+        Key: 'file_jobs',
+        Url: url,
+        Body: body,
+        ContentType: 'application/xml',
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 查询哈希值计算任务结果
+export const getFileHashResult = {
+  name: '查询哈希值计算任务结果',
+  fn: function getFileHashResult() {
+    const jobId = 'f3addcbd0a13811ed9b4ff5338d756fxx'; // 提交文件哈希值计算任务后会返回当前任务的jobId
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/file_jobs/' + jobId;
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'GET',
+        Key: 'file_jobs/' + jobId,
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 查询文件处理队列
+export const describeFileProcessQueues = {
+  name: '查询文件处理队列',
+  fn: function describeFileProcessQueues() {
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/file_queue';
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'GET',
+        Key: 'file_queue',
+        Url: url,
+        Query: {
+          // queueIds: '', // 非必须,队列 ID,以“,”符号分割字符串
+          state: 'Active', // 非必须,Active 表示队列内的作业会被调度执行。Paused 表示队列暂停,作业不再会被调度执行,队列内的所有作业状态维持在暂停状态,已经执行中的任务不受影响
+          pageNumber: 1, // 第几页,默认值1
+          pageSize: 10, // 非必须,每页个数,默认值10
+        },
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 更新文件处理队列
+export const updateFileProcessQueue = {
+  name: '更新文件处理队列',
+  fn: function updateFileProcessQueue() {
+    // 任务所在的队列 ID,请使用查询队列(https://cloud.tencent.com/document/product/460/46946)获取或前往万象控制台(https://cloud.tencent.com/document/product/460/46487)在存储桶中查询
+    const queueId = 'p6160ada105a7408e95aac015f4bf8xxx';
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/file_queue/' + queueId;
+    const url = 'https://' + host;
+    const body = COS.util.json2xml({
+      Request: {
+        Name: 'My-Queue-file', // 必须,队列名称,长度不超过128
+        State: 'Active', // 必须,Active 表示队列内的作业会被调度执行。Paused 表示队列暂停,作业不再会被调度执行,队列内的所有作业状态维持在暂停状态,已经执行中的任务不受影响。
+        NotifyConfig: {
+          // 必须,回调配置
+          State: 'On', // 必须,回调开关,Off/On,默认Off
+          Event: 'TaskFinish', // 回调事件,当 State=On时, 必选。任务完成:TaskFinish;工作流完成:WorkflowFinish
+          ResultFormat: 'XML', // 非必选,回调格式,JSON/XML
+          Type: 'Url', // 回调类型,当 State=On时, 必选,Url 或 TDMQ
+          Url: 'https://www.example.com', // 回调地址,当 State=On, 且Type=Url时, 必选
+          // MqMode: 'Off', // TDMQ 使用模式,当 State=On, 且Type=TDMQ时, 必选
+          // MqRegion: 'Off', // TDMQ 所属园区,当 State=On, 且Type=TDMQ时, 必选
+          // MqName: 'Off', // TDMQ 主题名称,当 State=On, 且Type=TDMQ时, 必选
+        },
+      },
+    });
+    cos.request(
+      {
+        Method: 'POST',
+        Key: 'file_queue/' + queueId,
+        Url: url,
+        Body: body,
+        ContentType: 'application/xml',
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 哈希值计算同步请求
+export const generateFileHash = {
+  name: '哈希值计算同步请求',
+  fn: function generateFileHash() {
+    const key = 'test.pdf';
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'GET',
+        Key: key,
+        Query: {
+          'ci-process': 'filehash', // 必须,操作类型,哈希值计算固定为:filehash
+          type: 'md5', // 必须,支持的哈希算法类型,有效值:md5、sha1、sha256
+          // 'addtoheader': false, // 非必须,是否将计算得到的哈希值,自动添加至文件的自定义header,格式为:x-cos-meta-md5/sha1/sha256;有效值:true、false,不填则默认为false。
+        },
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};

+ 122 - 0
node_modules/cos-js-sdk-v5/demo/CIDemos/index.js

@@ -0,0 +1,122 @@
+import * as common from './common.js';
+import * as taskAndWorkflow from './taskAndWorkflow.js';
+import * as picProcess from './picProcess.js';
+import * as ai from './ai.js';
+import * as mediaProcess from './mediaProcess.js';
+import * as docPreview from './docPreview.js';
+import * as audit from './audit.js';
+import * as fileProcess from './fileProcess.js';
+import * as asr from './asr.js';
+
+// 函数集合
+const moduleFn = {};
+// html排版
+const contentMap = {
+  common: {
+    title: 'Common',
+    functions: [],
+  },
+  taskAndWorkflow: {
+    title: '任务和工作流',
+    functions: [],
+  },
+  picProcess: {
+    title: '图片处理',
+    functions: [],
+  },
+  ai: {
+    title: 'AI识别',
+    functions: [],
+  },
+  mediaProcess: {
+    title: '媒体处理',
+    functions: [],
+  },
+  docPreview: {
+    title: '文档预览',
+    functions: [],
+  },
+  audit: {
+    title: '内容审核',
+    functions: [],
+  },
+  fileProcess: {
+    title: '文件处理',
+    functions: [],
+  },
+  asr: {
+    title: '智能语音',
+    functions: [],
+  },
+};
+
+function setContent(fnName, module, moduleName) {
+  const { name, fn } = module[fnName];
+  moduleFn[fnName] = module[fnName].fn;
+  contentMap[moduleName].functions.push({ name, fnName });
+}
+for (let fnName in common) {
+  setContent(fnName, common, 'common');
+}
+for (let fnName in taskAndWorkflow) {
+  setContent(fnName, taskAndWorkflow, 'taskAndWorkflow');
+}
+for (let fnName in picProcess) {
+  setContent(fnName, picProcess, 'picProcess');
+}
+for (let fnName in ai) {
+  setContent(fnName, ai, 'ai');
+}
+for (let fnName in mediaProcess) {
+  setContent(fnName, mediaProcess, 'mediaProcess');
+}
+for (let fnName in docPreview) {
+  setContent(fnName, docPreview, 'docPreview');
+}
+for (let fnName in audit) {
+  setContent(fnName, audit, 'audit');
+}
+for (let fnName in fileProcess) {
+  setContent(fnName, fileProcess, 'fileProcess');
+}
+for (let fnName in asr) {
+  setContent(fnName, asr, 'asr');
+}
+
+(function () {
+  const container = document.querySelector('.ci-main');
+  const html = [];
+  // 渲染html
+  for (let i in contentMap) {
+    const module = contentMap[i];
+    const content = `<div class="module-item"><h4>${module.title}</h4>`;
+    let a = '';
+    if (module.functions && module.functions.length > 0) {
+      a += module.functions
+        .map((item) => {
+          return `<a href="javascript:void(0)" data-method="${item.fnName}">${item.fnName}(${item.name})</a>`;
+        })
+        .join('');
+    }
+    html.push(content, a, '</div>');
+  }
+  container.innerHTML = html.join('');
+  container.onclick = function (e) {
+    if (e.target.tagName === 'A') {
+      const name = e.target.getAttribute('data-method').trim();
+      moduleFn[name]();
+    }
+  };
+
+  // 设置结果面板跟随窗口自适应高
+  const mainPanel = document.querySelector('.ci-main');
+  const resultPanel = document.querySelector('.result');
+  resultPanel.style.height = getPanelHeight();
+  window.onresize = function (e) {
+    resultPanel.style.height = getPanelHeight();
+  };
+
+  function getPanelHeight() {
+    return mainPanel.getBoundingClientRect().height - 80 + 'px';
+  }
+})();

File diff suppressed because it is too large
+ 1135 - 0
node_modules/cos-js-sdk-v5/demo/CIDemos/mediaProcess.js


+ 571 - 0
node_modules/cos-js-sdk-v5/demo/CIDemos/picProcess.js

@@ -0,0 +1,571 @@
+/**
+ * 图片处理demo集合
+ */
+
+// 获取带图片处理的访问url
+export const getImageUrl = {
+  name: '获取带图片处理的访问url',
+  fn: function getImageUrl() {
+    // 生成带图片处理参数的文件签名URL,过期时间设置为 30 分钟。
+    cos.getObjectUrl(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Key: '02.png',
+        Query: { 'imageMogr2/thumbnail/200x/': '' },
+        Expires: 1800,
+        Sign: true,
+      },
+      function (err, data) {
+        console.log('getObjectUrl with sign: ', err || (data && data.Url));
+      }
+    );
+
+    // 生成带图片处理参数的文件URL,不带签名。
+    cos.getObjectUrl(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Key: 'photo.png',
+        QueryString: `imageMogr2/thumbnail/200x/`,
+        Sign: false,
+      },
+      function (err, data) {
+        console.log('getObjectUrl without sign: ', err || (data && data.Url));
+      }
+    );
+  },
+};
+
+// 图片样式 - 查询样式
+export const describeImageStyles = {
+  name: '图片样式 - 查询样式',
+  fn: function describeImageStyles() {
+    const host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?style';
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'GET',
+        Url: url,
+        Query: {
+          'style-name': 'style_name', // 非必填,样式名称
+        },
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 图片样式 - 增加样式
+export const addImageStyle = {
+  name: '图片样式 - 增加样式',
+  fn: function addImageStyle() {
+    const host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?style';
+    const url = 'https://' + host;
+    const body = COS.util.json2xml({
+      AddStyle: {
+        StyleName: 'style_name1', // 必须,样式名称
+        StyleBody: 'imageMogr2/thumbnail/!50px', // 必须,样式详情
+      },
+    });
+    cos.request(
+      {
+        Method: 'PUT',
+        Url: url,
+        Body: body,
+        ContentType: 'application/xml',
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 图片样式 - 删除样式
+export const deleteImageStyle = {
+  name: '图片样式 - 删除样式',
+  fn: function deleteImageStyle() {
+    const host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?style';
+    const url = 'https://' + host;
+    const body = COS.util.json2xml({
+      DeleteStyle: {
+        StyleName: 'style_name1', // 必须,样式名称
+      },
+    });
+    cos.request(
+      {
+        Method: 'DELETE',
+        Url: url,
+        Body: body,
+        ContentType: 'application/xml',
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 开通 Guetzli 压缩
+export const openImageGuetzli = {
+  name: '开通 Guetzli 压缩',
+  fn: function openImageGuetzli() {
+    const host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?guetzli';
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'PUT',
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 查询 Guetzli 状态
+export const describeImageGuetzli = {
+  name: '查询 Guetzli 状态',
+  fn: function describeImageGuetzli() {
+    const host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?guetzli';
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'GET',
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 关闭 Guetzli 压缩
+export const closeImageGuetzli = {
+  name: '关闭 Guetzli 压缩',
+  fn: function closeImageGuetzli() {
+    const host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?guetzli';
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'DELETE',
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 上传时使用图片处理
+export const uploadPicOperation = {
+  name: '上传时使用图片处理',
+  fn: function uploadPicOperation() {
+    util.selectLocalFile(function (files) {
+      const file = files && files[0];
+      if (!file) return;
+      if (file.type.indexOf('image') < 0) {
+        console.error('Please select a photo to upload!');
+        return;
+      }
+      if (file.size > 1024 * 1024) {
+        cos.sliceUploadFile(
+          {
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region,
+            Key: file.name,
+            Body: file,
+            Headers: {
+              // 通过 imageMogr2 接口使用图片缩放功能:指定图片宽度为 200,宽度等比压缩
+              'Pic-Operations': JSON.stringify({
+                is_pic_info: 1,
+                rules: [{ fileid: 'desample_photo.jpg', rule: 'imageMogr2/thumbnail/200x/' }],
+              }),
+            },
+            onHashProgress: function (progressData) {
+              console.log('onHashProgress', JSON.stringify(progressData));
+            },
+            onProgress: function (progressData) {
+              console.log('onProgress', JSON.stringify(progressData));
+            },
+          },
+          function (err, data) {
+            console.log('uploadPicOperation:', err || data);
+          }
+        );
+      } else {
+        cos.putObject(
+          {
+            Bucket: config.Bucket, // Bucket 格式:test-1250000000
+            Region: config.Region,
+            Key: file.name,
+            Body: file,
+            Headers: {
+              // 通过 imageMogr2 接口进行 avif 压缩,可以根据需要压缩的类型填入不同的压缩格式:webp/heif/tpg/avif/svgc
+              'Pic-Operations':
+                '{"is_pic_info": 1, "rules": [{"fileid": "desample_photo.jpg", "rule": "imageMogr2/format/avif"}]}',
+            },
+            onHashProgress: function (progressData) {
+              console.log('onHashProgress', JSON.stringify(progressData));
+            },
+            onProgress: function (progressData) {
+              console.log('onProgress', JSON.stringify(progressData));
+            },
+          },
+          function (err, data) {
+            console.log('uploadPicOperation:', err || data);
+          }
+        );
+      }
+    });
+  },
+};
+
+// 对云上数据处理
+export const requestPicOperation = {
+  name: '对云上数据处理',
+  fn: function requestPicOperation() {
+    // 文字水印示例
+    const text = '腾讯云万象优图';
+    const color = '#3D3D3D';
+    // 经过安全base64编码 使用 COS.util.encodeBase64 方法需要sdk版本至少为1.4.18
+    const textBase64 = COS.util.encodeBase64(text, true);
+    const colorBase64 = COS.util.encodeBase64(color, true);
+    // 生成一个文字水印
+    const waterMarkRule = `watermark/2/text/${textBase64}/fill/${colorBase64}/fontsize/20/dissolve/50/gravity/northeast/dx/20/dy/20/batch/1/degree/45`;
+    const picOperations = JSON.stringify({
+      is_pic_info: 1, // 固定
+      // fileid 设置和Key相同可实现只保留处理后的图片而不保留原图
+      rules: [{ fileid: 'desample_photo.jpg', rule: waterMarkRule }],
+    });
+
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Key: '02.png',
+        Method: 'GET',
+        Action: 'exif',
+        RawBody: true,
+        // Headers: {
+        //   // 通过 imageMogr2 接口使用图片缩放功能:指定图片宽度为 200,宽度等比压缩
+        //   'Pic-Operations': picOperations,
+        // },
+      },
+      function (err, data) {
+        const info = JSON.parse(data.Body);
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 下载时使用图片压缩
+export const getObjectPicOperation = {
+  name: '下载时使用图片压缩',
+  fn: function getObjectPicOperation() {
+    cos.getObject(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Key: '1.png',
+        QueryString: `imageMogr2/format/avif`, // 可以根据需要压缩的类型填入不同的压缩格式:webp/heif/tpg/avif/svgc
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 异常图片检测
+export const createImageInspectJob = {
+  name: '异常图片检测',
+  fn: function createImageInspectJob() {
+    const key = '1.png';
+    cos.request(
+      {
+        Bucket: config.Bucket,
+        Region: config.Region,
+        Method: 'GET',
+        Key: key,
+        RawBody: true,
+        Query: {
+          'ci-process': 'ImageInspect', // 必须,操作类型,异常图片检测固定为:ImageInspect
+        },
+      },
+      function (err, data) {
+        // 从响应数据中解析出异常图片检测结果
+        let body = {};
+        if (data && data.Body) {
+          body = JSON.parse(data.Body) || {};
+          if (body) {
+            data.body = body;
+          }
+        }
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 查询图片处理队列
+export const describePicProcessQueues = {
+  name: '查询图片处理队列',
+  fn: function describePicProcessQueues() {
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/picqueue';
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'GET',
+        Key: 'picqueue',
+        Url: url,
+        Query: {
+          // queueIds: '', // 非必须,队列 ID,以“,”符号分割字符串
+          state: 'Active', // 非必须,1. Active 表示队列内的作业会被媒体处理服务调度执行。2. Paused 表示队列暂停,作业不再会被媒体处理调度执行,队列内的所有作业状态维持在暂停状态,已经执行中的任务不受影响。
+          pageNumber: 1, // 非必须,第几页,默认值1
+          pageSize: 10, // 非必须,每页个数,默认值10
+        },
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 更新图片处理队列
+export const updatePicProcessQueue = {
+  name: '更新图片处理队列',
+  fn: function updatePicProcessQueue() {
+    // 任务所在的队列 ID,请使用查询队列(https://cloud.tencent.com/document/product/460/46946)获取或前往万象控制台(https://cloud.tencent.com/document/product/460/46487)在存储桶中查询
+    const queueId = 'p882d181160d84feca27d9376e17c4xxx';
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/picqueue/' + queueId;
+    const url = 'https://' + host;
+    const body = COS.util.json2xml({
+      Request: {
+        Name: 'My-Queue-Pic', // 必须,队列名称,长度不超过128
+        State: 'Active', // 必须,Active 表示队列内的作业会被调度执行。Paused 表示队列暂停,作业不再会被调度执行,队列内的所有作业状态维持在暂停状态,已经执行中的任务不受影响。
+        NotifyConfig: {
+          // 必须,回调配置
+          State: 'On', // 必须,回调开关,Off/On,默认Off
+          Event: 'TaskFinish', // 回调事件,当 State=On时, 必选。任务完成:TaskFinish;工作流完成:WorkflowFinish
+          ResultFormat: 'XML', // 非必选,回调格式,JSON/XML
+          Type: 'Url', // 回调类型,当 State=On时, 必选,Url 或 TDMQ
+          Url: 'https://www.example.com', // 回调地址,当 State=On, 且Type=Url时, 必选
+          // MqMode: 'Off', // TDMQ 使用模式,当 State=On, 且Type=TDMQ时, 必选
+          // MqRegion: 'Off', // TDMQ 所属园区,当 State=On, 且Type=TDMQ时, 必选
+          // MqName: 'Off', // TDMQ 主题名称,当 State=On, 且Type=TDMQ时, 必选
+        },
+      },
+    });
+    cos.request(
+      {
+        Method: 'POST',
+        Key: 'picqueue/' + queueId,
+        Url: url,
+        Body: body,
+        ContentType: 'application/xml',
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 查询原图保护状态
+export const describeOriginProtect = {
+  name: '查询原图保护状态',
+  fn: function describeOriginProtect() {
+    const host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?origin-protect';
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'GET',
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 开通原图保护
+export const openOriginProtect = {
+  name: '开通原图保护',
+  fn: function openOriginProtect() {
+    const host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?origin-protect';
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'PUT',
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 关闭原图保护
+export const closeOriginProtect = {
+  name: '关闭原图保护',
+  fn: function closeOriginProtect() {
+    const host = config.Bucket + '.pic.' + config.Region + '.myqcloud.com/?origin-protect';
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'DELETE',
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 开通图片处理(异步)服务
+export const CreatePicProcessBucket = {
+  name: '开通图片处理(异步)服务',
+  fn: function CreatePicProcessBucket() {
+    const key = 'picbucket'; // 固定值
+    const host = config.Bucket + '.ci.' + config.Region + '.myqcloud.com/' + key;
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'POST',
+        Key: key,
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};
+
+// 查询图片处理(异步)服务
+export const DescribePicProcessBuckets = {
+  name: '查询图片处理(异步)服务',
+  fn: function DescribePicProcessBuckets() {
+    const key = 'picbucket'; // 固定值
+    const host = 'ci.' + config.Region + '.myqcloud.com/' + key;
+    const url = 'https://' + host;
+    cos.request(
+      {
+        Method: 'GET',
+        Key: key,
+        Url: url,
+      },
+      function (err, data) {
+        if (err) {
+          // 处理请求失败
+          console.log(err);
+        } else {
+          // 处理请求成功
+          console.log(data);
+        }
+      }
+    );
+  },
+};

File diff suppressed because it is too large
+ 1012 - 0
node_modules/cos-js-sdk-v5/demo/CIDemos/taskAndWorkflow.js


+ 40 - 0
node_modules/cos-js-sdk-v5/demo/common/async.js

@@ -0,0 +1,40 @@
+var eachLimit = function (arr, limit, iterator, callback) {
+    callback = callback || function () {};
+    if (!arr.length || limit <= 0) {
+        return callback();
+    }
+
+    var completed = 0;
+    var started = 0;
+    var running = 0;
+
+    (function replenish () {
+        if (completed >= arr.length) {
+            return callback();
+        }
+
+        while (running < limit && started < arr.length) {
+            started += 1;
+            running += 1;
+            iterator(arr[started - 1], function (err) {
+
+                if (err) {
+                    callback(err);
+                    callback = function () {};
+                } else {
+                    completed += 1;
+                    running -= 1;
+                    if (completed >= arr.length) {
+                        callback();
+                    } else {
+                        replenish();
+                    }
+                }
+            });
+        }
+    })();
+};
+
+var Async = {
+    eachLimit: eachLimit,
+};

File diff suppressed because it is too large
+ 219 - 0
node_modules/cos-js-sdk-v5/demo/common/cos-auth.js


File diff suppressed because it is too large
+ 1 - 0
node_modules/cos-js-sdk-v5/demo/common/cos-auth.min.js


File diff suppressed because it is too large
+ 2 - 0
node_modules/cos-js-sdk-v5/demo/common/jquery-3.3.1.min.js


File diff suppressed because it is too large
+ 29 - 0
node_modules/cos-js-sdk-v5/demo/common/lodash.core.min.js


File diff suppressed because it is too large
+ 6 - 0
node_modules/cos-js-sdk-v5/demo/common/vue.min.js


BIN
node_modules/cos-js-sdk-v5/demo/cors.png


+ 53 - 0
node_modules/cos-js-sdk-v5/demo/crc64.html

@@ -0,0 +1,53 @@
+
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport"
+          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
+    <meta http-equiv="X-UA-Compatible" content="ie=edge">
+    <title>CRC64</title>
+    <style>
+        h1 {
+            font-weight: normal;
+        }
+    </style>
+</head>
+<body>
+
+<div>
+    <h1>JS 计算 CRC64</h1>
+    <form id="form">
+        <label>选择文件,计算 crc64:</label>
+        <input id="file" type="file">
+    </form>
+    <div id="msg"></div>
+</div>
+
+<script src="./crc64.js"></script>
+<script>
+    var el = function (id) {
+        return document.getElementById(id);
+    };
+    var calc = function (file) {
+        var time0 = Date.now();
+        CRC64.file_crc64(file, function (err, hash) {
+            if (err) return console.log('crc64 error:', err);
+            var time1 = Date.now();
+            el('msg').innerHTML = 'cost ' + (time1 - time0) + 'ms, crc64=' + hash;
+            el('form').reset();
+        }, function (percent) {
+            el('msg').innerHTML = (percent * 100).toFixed(2) + '%';
+        });
+    };
+    el('file').onchange = function () {
+        var file = this.files[0];
+        calc(file);
+    };
+
+    // calc string crc64
+    console.log(CRC64.crc64('123456789'));
+</script>
+
+</body>
+</html>

File diff suppressed because it is too large
+ 17990 - 0
node_modules/cos-js-sdk-v5/demo/crc64.js


File diff suppressed because it is too large
+ 1822 - 0
node_modules/cos-js-sdk-v5/demo/demo.js


+ 1 - 0
node_modules/cos-js-sdk-v5/demo/empty.html

@@ -0,0 +1 @@
+This is a helper for "simple-form.html".

+ 19 - 0
node_modules/cos-js-sdk-v5/demo/folder/index.html

@@ -0,0 +1,19 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport"
+          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
+    <meta http-equiv="X-UA-Compatible" content="ie=edge">
+    <title>COS 文件管理</title>
+    <link rel="stylesheet" href="style.css">
+</head>
+<body>
+
+<div class="page">
+    <h1>COS 文件管理</h1>
+    <div id="app">待实现...</div>
+</div>
+
+</body>
+</html>

+ 332 - 0
node_modules/cos-js-sdk-v5/demo/index.html

@@ -0,0 +1,332 @@
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta
+      name="viewport"
+      content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
+    />
+    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
+    <title>cos-js-sdk-v5</title>
+    <style>
+      body {
+        font-family: 'Microsoft YaHei';
+      }
+      .page {
+        min-width: 1000px;
+        margin: 0 auto;
+        padding: 0 50px;
+      }
+      .main-wrap {
+        float: left;
+        width: 100%;
+      }
+      .main {
+        margin-right: 700px;
+        margin-bottom: 20px;
+        display: none;
+      }
+      .main.show {
+        display: block;
+      }
+      .siderbar {
+        float: left;
+        width: 600px;
+        margin-left: -600px;
+        margin-bottom: 20px;
+        padding-top: 60px;
+      }
+      .result {
+        line-height: 1.3;
+        font-size: 13px;
+        font-family: monospace;
+        border: 1px solid #006eff;
+        margin: 0;
+        height: 200px;
+        overflow: auto;
+        box-sizing: border-box;
+        padding: 5px;
+      }
+      h1 {
+        font-weight: normal;
+        color: #333;
+      }
+      a {
+        color: #006eff;
+        background-color: transparent;
+        padding: 8px 16px;
+        line-height: 1.3;
+        display: inline-block;
+        text-align: center;
+        margin: 0 8px 8px 0;
+        border: 1px solid #006eff;
+        font-size: 14px;
+        text-decoration: none;
+      }
+      a:hover {
+        color: #fff;
+        background-color: #006eff;
+      }
+      hr {
+        border: 0;
+        border-top: 1px solid #006eff;
+      }
+      .demo-select-content {
+        display: inline-block;
+        font-size: 0;
+        margin-left: 20px;
+      }
+      .demo-select-content div {
+        display: inline-block;
+        font-size: 16px;
+        border: solid 1px #ddd;
+        padding: 2px 6px;
+        cursor: pointer;
+      }
+      .demo-select-content div.active {
+        border-color: #006eff;
+        color: #006eff;
+      }
+    </style>
+  </head>
+  <body>
+    <div class="page">
+      <h1>
+        cos-js-sdk-v5
+        <div class="demo-select-content">
+          <div class="active" id="showCosDemo">cos demo</div>
+          <div id="showCiDemo">ci demo</div>
+        </div>
+      </h1>
+      <div class="main-wrap">
+        <div class="main cos-main show"></div>
+        <div class="main ci-main"></div>
+      </div>
+      <div class="siderbar">
+        <pre class="result"></pre>
+      </div>
+    </div>
+
+    <script src="../dist/cos-js-sdk-v5.js"></script>
+    <script src="./demo.js"></script>
+    <script type="module" src="./CIDemos/index.js"></script>
+
+    <script>
+      (function () {
+        var showCosDemoBtn = document.querySelector('#showCosDemo');
+        var showCiDemobtn = document.querySelector('#showCiDemo');
+        var cosMain = document.querySelector('.cos-main');
+        var ciMain = document.querySelector('.ci-main');
+        showCosDemoBtn.addEventListener('click', function (e) {
+          showCosDemoBtn.className = 'active';
+          showCiDemobtn.className = '';
+          cosMain.className = 'main cos-main show';
+          ciMain.className = 'main cos-main';
+        });
+        showCiDemobtn.addEventListener('click', function (e) {
+          showCosDemoBtn.className = '';
+          showCiDemobtn.className = 'active';
+          cosMain.className = 'main cos-main';
+          ciMain.className = 'main cos-main show';
+        });
+
+        // config 替换成自己的存储桶和账号信息
+        var config = {
+          Bucket: 'test-1250000000',
+          Region: 'ap-guangzhou',
+          Uin: '10001',
+        };
+        var getAuthorization = function (options, callback) {
+          // 格式一、(推荐)后端通过获取临时密钥给到前端,前端计算签名
+          // 服务端 JS 和 PHP 例子:https://github.com/tencentyun/cos-js-sdk-v5/blob/master/server/
+          // 服务端其他语言参考 COS STS SDK :https://github.com/tencentyun/qcloud-cos-sts-sdk
+          var url = '/sts'; // 如果是 npm run sts.js 起的 nodejs server,使用这个
+          var xhr = new XMLHttpRequest();
+          xhr.open('POST', url, true);
+          xhr.setRequestHeader('Content-Type', 'application/json');
+          xhr.onload = function (e) {
+            try {
+              var data = JSON.parse(e.target.responseText);
+              var credentials = data.credentials;
+            } catch (e) {}
+            if (!data || !credentials) {
+              return logger.error('credentials invalid:\n' + JSON.stringify(data, null, 2));
+            }
+            callback({
+              TmpSecretId: credentials.tmpSecretId,
+              TmpSecretKey: credentials.tmpSecretKey,
+              SecurityToken: credentials.sessionToken,
+              StartTime: data.startTime, // 时间戳,单位秒,如:1580000000,建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
+              ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000000
+              ScopeLimit: true, // 细粒度控制权限需要设为 true,会限制密钥只在相同请求时重复使用
+            });
+          };
+          xhr.send(JSON.stringify(options.Scope));
+
+          // // 格式二、(推荐)【细粒度控制权限】后端通过获取临时密钥给到前端,前端只有相同请求才重复使用临时密钥,后端可以通过 Scope 细粒度控制权限
+          // // 服务端例子:https://github.com/tencentyun/qcloud-cos-sts-sdk/edit/master/scope.md
+          // // var url = '../server/sts.php'; // 如果起的是 php server 用这个
+          // var url = '/sts-scope'; // 如果是 npm run sts.js 起的 nodejs server,使用这个
+          // var xhr = new XMLHttpRequest();
+          // xhr.open('POST', url, true);
+          // xhr.setRequestHeader('Content-Type', 'application/json');
+          // xhr.onload = function (e) {
+          //     try {
+          //         var data = JSON.parse(e.target.responseText);
+          //         var credentials = data.credentials;
+          //     } catch (e) {
+          //     }
+          //     if (!data || !credentials) {
+          //         return logger.error('credentials invalid:\n' + JSON.stringify(data, null, 2))
+          //     };
+          //     callback({
+          //         TmpSecretId: credentials.tmpSecretId,
+          //         TmpSecretKey: credentials.tmpSecretKey,
+          //         SecurityToken: credentials.sessionToken,
+          //         StartTime: data.startTime, // 时间戳,单位秒,如:1580000000,建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
+          //         ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000000
+          //         ScopeLimit: true, // 细粒度控制权限需要设为 true,会限制密钥只在相同请求时重复使用
+          //     });
+          // };
+          // xhr.send(JSON.stringify(options.Scope));
+
+          // // 格式三、(不推荐,分片上传权限不好控制)前端每次请求前都需要通过 getAuthorization 获取签名,后端使用固定密钥或临时密钥计算签名返回给前端
+          // // 服务端获取签名,请参考对应语言的 COS SDK:https://cloud.tencent.com/document/product/436/6474
+          // // 注意:这种有安全风险,后端需要通过 method、pathname 严格控制好权限,比如不允许 put / 等
+          // var method = (options.Method || 'get').toLowerCase();
+          // var query = options.Query || {};
+          // var headers = options.Headers || {};
+          // var pathname = options.Pathname || '/';
+          // // var url = 'http://127.0.0.1:3000/auth';
+          // var url = '../server/auth.php';
+          // var xhr = new XMLHttpRequest();
+          // var data = {
+          //     method: method,
+          //     pathname: pathname,
+          //     query: query,
+          //     headers: headers,
+          // };
+          // xhr.open('POST', url, true);
+          // xhr.setRequestHeader('content-type', 'application/json');
+          // xhr.onload = function (e) {
+          //     try {
+          //         var data = JSON.parse(e.target.responseText);
+          //     } catch (e) {
+          //     }
+          //     if (!data || !data.authorization) return console.error('authorization invalid');
+          //     callback({
+          //         Authorization: data.authorization,
+          //         // SecurityToken: data.sessionToken, // 如果使用临时密钥,需要把 sessionToken 传给 SecurityToken
+          //     });
+          // };
+          // xhr.send(JSON.stringify(data));
+
+          // // 格式四、(不推荐,适用于前端调试,避免泄露密钥)前端使用固定密钥计算签名
+          // var authorization = COS.getAuthorization({
+          //     SecretId: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', // 可传固定密钥或者临时密钥
+          //     SecretKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', // 可传固定密钥或者临时密钥
+          //     Method: options.Method,
+          //     Pathname: options.Pathname,
+          //     Query: options.Query,
+          //     Headers: options.Headers,
+          //     Expires: 900,
+          // });
+          // callback({
+          //     Authorization: authorization,
+          //     // SecurityToken: credentials.sessionToken, // 如果使用临时密钥,需要传 SecurityToken
+          // });
+        };
+
+        var cos = new COS({
+          getAuthorization: getAuthorization,
+          UploadCheckContentMd5: true,
+        });
+
+        var util = {
+          createFile: function (options) {
+            var buffer = new ArrayBuffer(options.size || 0);
+            var arr = new Uint8Array(buffer);
+            [].forEach.call(arr, function (char, i) {
+              arr[i] = 0;
+            });
+            var opt = {};
+            options.type && (opt.type = options.type);
+            var blob = new Blob([buffer], options);
+            return blob;
+          },
+          selectLocalFile: function (onChange) {
+            var id = 'file_selector';
+            var input = document.createElement('input');
+            input.style = 'width:0;height:0;border:0;margin:0;padding:0;';
+            input.type = 'file';
+            input.id = id;
+            input.onchange = function (e) {
+              var files = this.files;
+              if (!files.length) return;
+              onChange && onChange(files);
+              document.body.removeChild(input);
+            };
+            document.body.appendChild(input);
+            input.click();
+          },
+        };
+
+        // 对更多字符编码的 url encode 格式
+        var camSafeUrlEncode = function (str) {
+          return encodeURIComponent(str)
+            .replace(/!/g, '%21')
+            .replace(/'/g, '%27')
+            .replace(/\(/g, '%28')
+            .replace(/\)/g, '%29')
+            .replace(/\*/g, '%2A');
+        };
+
+        var pre = document.querySelector('.result');
+        var showLogText = function (text, color) {
+          if (typeof text === 'object') {
+            try {
+              text = JSON.stringify(text);
+            } catch (e) {}
+          }
+          var div = document.createElement('div');
+          div.innerText = text;
+          color && (div.style.color = color);
+          pre.appendChild(div);
+          pre.style.display = 'block';
+          pre.scrollTop = pre.scrollHeight;
+        };
+
+        var logger = {
+          log: function (text) {
+            console.log.apply(console, arguments);
+            var args = [].map.call(arguments, function (v) {
+              return typeof v === 'object' ? JSON.stringify(v, null, 2) : v;
+            });
+
+            var logStr = args.join(' ');
+
+            if (logStr.length > 1000000) {
+              logStr =
+                logStr.slice(0, 1000000) + '...content is too long, the first 1000000 characters are intercepted';
+            }
+
+            showLogText(logStr);
+          },
+          error: function (text) {
+            console.error(text);
+            showLogText(text, 'red');
+          },
+        };
+
+        /**
+         * 这里demo为了方便挂在了window上 实际使用请结合项目比如可使用模块导出
+         * */
+        window.config = config;
+        window.cos = cos;
+        window.util = util;
+        window.logger = logger;
+        window.camSafeUrlEncode = camSafeUrlEncode;
+      })();
+    </script>
+  </body>
+</html>

+ 101 - 0
node_modules/cos-js-sdk-v5/demo/mime-limit.html

@@ -0,0 +1,101 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>上传限制 Content-Type</title>
+    <style>
+        h1, h2 {
+            font-weight: normal;
+        }
+
+        #msg {
+            margin-top: 10px;
+        }
+    </style>
+</head>
+<body>
+
+<h1>上传限制 Content-Type</h1>
+
+<input id="fileSelector" type="file">
+<input id="submitBtn" type="submit">
+
+<div id="msg"></div>
+
+<script src="../dist/cos-js-sdk-v5.js"></script>
+<script>
+    (function () {
+        // 计算签名
+        var getUploadSign = function (options, callback) {
+            var url = '/uploadSign?filename=' + encodeURIComponent(options.filename) + '&_=' + Date.now();
+            var xhr = new XMLHttpRequest();
+            xhr.open('POST', url, true);
+            xhr.onload = function (e) {
+                var token;
+                try {
+                    token = (new Function('return ' + xhr.responseText))();
+                } catch (e) {}
+                if (token) {
+                    callback(null, token);
+                } else {
+                    console.error(xhr.responseText);
+                    callback('获取签名出错');
+                }
+            };
+            xhr.onerror = function (e) {
+                callback('获取签名出错');
+            };
+            xhr.send();
+        };
+
+        // 上传文件
+        var uploadFile = function (file, callback) {
+            getUploadSign({ filename: file.name }, function (err, info) {
+                if (err) {
+                    alert(err);
+                    return;
+                }
+                var signMap = info.signMap;
+                var mimeLimit = info.mimeLimit;
+                var allowActions = ['ListMultipartUploads', 'ListParts', 'InitiateMultipartUpload', 'UploadPart', 'CompleteMultipartUpload', 'PutObject'];
+                var cos = new COS({
+                    getAuthorization: function (opt, cb) {
+                        var action = opt.Scope[0].action.split(':')[1];
+                        if (allowActions.indexOf(action) === -1) return console.error('action not allow');
+                        var auth = signMap[action];
+                        cb({ Authorization: auth });
+                    },
+                });
+                cos.uploadFile({
+                    Bucket: info.bucket,
+                    Region: info.region,
+                    Key: info.key,
+                    Body: file,
+                    SliceSize: 1024 * 1024 * 8,
+                    ChunkSize: 1024 * 1024 * 8,
+                    Headers: {
+                        'x-cos-mime-limit': mimeLimit,
+                    },
+                }, function (err, data) {
+                    callback(err, data);
+                });
+            });
+        };
+
+        // 监听表单提交
+        document.getElementById('submitBtn').onclick = function (e) {
+            var file = document.getElementById('fileSelector').files[0];
+            if (!file) {
+                document.getElementById('msg').innerText = '未选择上传文件';
+                return;
+            }
+            file && uploadFile(file, function (err, data) {
+                console.log(err || data);
+                document.getElementById('msg').innerText = err ? '上传失败:' + err.code + '(' + err.message + ')' : ('上传成功,ETag=' + data.ETag);
+            });
+        };
+    })();
+</script>
+
+</body>
+</html>

+ 1 - 0
node_modules/cos-js-sdk-v5/demo/noSDK/empty.html

@@ -0,0 +1 @@
+This is a helper for "simple-form.html".

+ 191 - 0
node_modules/cos-js-sdk-v5/demo/noSDK/form_sign.html

@@ -0,0 +1,191 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <title>Form 表单简单上传(兼容 IE8)(服务端计算签名)</title>
+    <style>
+      h1,
+      h2 {
+        font-weight: normal;
+      }
+      #msg {
+        margin-top: 10px;
+      }
+    </style>
+  </head>
+  <body>
+    <h1>Form 表单简单上传(兼容 IE8)(服务端计算签名)</h1>
+    <div>最低兼容到 IE6 上传,不支持 onprogress</div>
+
+    <form
+      id="form"
+      target="submitTarget"
+      action=""
+      method="post"
+      enctype="multipart/form-data"
+      accept="*/*"
+    >
+      <input id="name" name="name" type="hidden" value="" />
+      <input name="success_action_status" type="hidden" value="200" />
+      <input
+        id="success_action_redirect"
+        name="success_action_redirect"
+        type="hidden"
+        value=""
+      />
+      <input id="key" name="key" type="hidden" value="" />
+      <input id="policy" name="policy" type="hidden" value="" />
+      <input
+        id="q-sign-algorithm"
+        name="q-sign-algorithm"
+        type="hidden"
+        value=""
+      />
+      <input id="q-ak" name="q-ak" type="hidden" value="" />
+      <input id="q-key-time" name="q-key-time" type="hidden" value="" />
+      <input id="q-signature" name="q-signature" type="hidden" value="" />
+      <input name="Content-Type" type="hidden" value="" />
+      <input
+        id="x-cos-security-token"
+        name="x-cos-security-token"
+        type="hidden"
+        value=""
+      />
+
+      <!-- file 字段放在表单最后,避免文件内容过长影响签名判断和鉴权 -->
+      <input id="fileSelector" name="file" type="file" />
+      <input id="submitBtn" type="button" value="提交" />
+    </form>
+    <iframe
+      id="submitTarget"
+      name="submitTarget"
+      style="display: none"
+      frameborder="0"
+    ></iframe>
+
+    <div id="msg"></div>
+
+    <script>
+      (function () {
+        const form = document.getElementById('form');
+        let prefix = '';
+
+        // 对更多字符编码的 url encode 格式
+        const camSafeUrlEncode = function (str) {
+          return encodeURIComponent(str)
+            .replace(/!/g, '%21')
+            .replace(/'/g, '%27')
+            .replace(/\(/g, '%28')
+            .replace(/\)/g, '%29')
+            .replace(/\*/g, '%2A');
+        };
+
+        // 计算签名
+        const getAuthorization = function (opt, callback) {
+          // 替换为自己服务端地址 获取post上传签名
+          const url = `http://127.0.0.1:3000/post-policy?ext=${opt.ext || ''}`;
+          const xhr = new XMLHttpRequest();
+          xhr.open('GET', url, true);
+          xhr.onload = function (e) {
+            let credentials;
+            try {
+              const result = JSON.parse(e.target.responseText);
+              credentials = result;
+            } catch (e) {
+              callback('获取签名出错');
+            }
+            if (credentials) {
+              callback(null, {
+                securityToken: credentials.securityToken,
+                cosKey: credentials.cosKey,
+                cosHost: credentials.cosHost,
+                policy: credentials.policy,
+                qAk: credentials.qAk,
+                qKeyTime: credentials.qKeyTime,
+                qSignAlgorithm: credentials.qSignAlgorithm,
+                qSignature: credentials.qSignature,
+              });
+            } else {
+              console.error(xhr.responseText);
+              callback('获取签名出错');
+            }
+          };
+          xhr.send();
+        };
+
+        // 监听上传完成
+        let Key;
+        const submitTarget = document.getElementById('submitTarget');
+        const showMessage = function (err, data) {
+          console.log(err || data);
+          document.getElementById('msg').innerText = err
+            ? err
+            : '上传成功,ETag=' + data.ETag;
+        };
+        submitTarget.onload = function () {
+          let search;
+          try {
+            search = submitTarget.contentWindow.location.search.substr(1);
+          } catch (e) {
+            showMessage('文件 ' + Key + ' 上传失败');
+          }
+          if (search) {
+            const items = search.split('&');
+            let i = 0;
+            let arr = [];
+            const data = {};
+            for (i = 0; i < items.length; i++) {
+              arr = items[i].split('=');
+              data[arr[0]] = decodeURIComponent(arr[1] || '');
+            }
+            showMessage(null, {
+              url: prefix + camSafeUrlEncode(Key).replace(/%2F/g, '/'),
+              ETag: data.etag,
+            });
+          } else {
+          }
+        };
+
+        // 发起上传
+        document.getElementById('submitBtn').onclick = function (e) {
+          const filePath = document.getElementById('fileSelector').value;
+          if (!filePath) {
+            document.getElementById('msg').innerText = '未选择上传文件';
+            return;
+          }
+          let ext = '';
+          const lastDotIndex = filePath.lastIndexOf('.');
+          if (lastDotIndex > -1) {
+            // 这里获取文件后缀 由服务端生成最终上传的路径
+            ext = filePath.substring(lastDotIndex + 1);
+          }
+          getAuthorization({ ext }, function (err, AuthData) {
+            if (err) {
+              alert(err);
+              return;
+            }
+            const protocol =
+              location.protocol === 'https:' ? 'https:' : 'http:';
+            prefix = protocol + '//' + AuthData.cosHost;
+            form.action = prefix;
+            Key = AuthData.cosKey;
+            // 在当前目录下放一个空的 empty.html 以便让接口上传完成跳转回来
+            document.getElementById('success_action_redirect').value =
+              location.href.substr(0, location.href.lastIndexOf('/') + 1) +
+              'empty.html';
+            document.getElementById('key').value = AuthData.cosKey;
+            document.getElementById('policy').value = AuthData.policy;
+            document.getElementById('q-sign-algorithm').value =
+              AuthData.qSignAlgorithm;
+            document.getElementById('q-ak').value = AuthData.qAk;
+            document.getElementById('q-key-time').value = AuthData.qKeyTime;
+            document.getElementById('q-signature').value = AuthData.qSignature;
+            document.getElementById('x-cos-security-token').value =
+              AuthData.securityToken || '';
+            form.submit();
+          });
+        };
+      })();
+    </script>
+  </body>
+</html>

+ 193 - 0
node_modules/cos-js-sdk-v5/demo/noSDK/form_sts.html

@@ -0,0 +1,193 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <title>Form 表单简单上传(兼容 IE8)(前端计算签名)</title>
+    <style>
+      h1,
+      h2 {
+        font-weight: normal;
+      }
+      #msg {
+        margin-top: 10px;
+      }
+    </style>
+  </head>
+  <body>
+    <h1>Form 表单简单上传(兼容 IE8)(前端计算签名)</h1>
+    <div>最低兼容到 IE6 上传,不支持 onprogress</div>
+
+    <form
+      id="form"
+      target="submitTarget"
+      action=""
+      method="post"
+      enctype="multipart/form-data"
+      accept="*/*"
+    >
+      <input id="name" name="name" type="hidden" value="" />
+      <input name="success_action_status" type="hidden" value="200" />
+      <input
+        id="success_action_redirect"
+        name="success_action_redirect"
+        type="hidden"
+        value=""
+      />
+      <input id="key" name="key" type="hidden" value="" />
+      <input id="policy" name="policy" type="hidden" value="" />
+      <input
+        id="q-sign-algorithm"
+        name="q-sign-algorithm"
+        type="hidden"
+        value=""
+      />
+      <input id="q-ak" name="q-ak" type="hidden" value="" />
+      <input id="q-key-time" name="q-key-time" type="hidden" value="" />
+      <input id="q-signature" name="q-signature" type="hidden" value="" />
+      <input name="Content-Type" type="hidden" value="" />
+      <input
+        id="x-cos-security-token"
+        name="x-cos-security-token"
+        type="hidden"
+        value=""
+      />
+
+      <!-- file 字段放在表单最后,避免文件内容过长影响签名判断和鉴权 -->
+      <input id="fileSelector" name="file" type="file" />
+      <input id="submitBtn" type="button" value="提交" />
+    </form>
+    <iframe
+      id="submitTarget"
+      name="submitTarget"
+      style="display: none"
+      frameborder="0"
+    ></iframe>
+
+    <div id="msg"></div>
+
+    <!-- 签名计算 可通过(https://unpkg.com/cos-js-sdk-v5/demo/common/cos-auth.min.js)下载 -->
+    <script src="../common/cos-auth.js"></script>
+    <script>
+      (function () {
+        // 请求用到的参数
+        const Bucket = 'examplebucket-1250000000'; // 替换为自己的存储桶
+        const Region = 'ap-beijing'; // 替换为自己的存储桶地域
+        const protocol = location.protocol === 'https:' ? 'https:' : 'http:';
+        const prefix =
+          protocol + '//' + Bucket + '.cos.' + Region + '.myqcloud.com'; // prefix 用于拼接请求
+        const form = document.getElementById('form');
+        form.action = prefix;
+
+        // 对更多字符编码的 url encode 格式
+        const camSafeUrlEncode = function (str) {
+          return encodeURIComponent(str)
+            .replace(/!/g, '%21')
+            .replace(/'/g, '%27')
+            .replace(/\(/g, '%28')
+            .replace(/\)/g, '%29')
+            .replace(/\*/g, '%2A');
+        };
+
+        // 计算签名
+        const getAuthorization = function (opt, callback) {
+          // 替换为自己服务端地址 获取临时密钥
+          const url = `http://127.0.0.1:3000/sts`;
+          const xhr = new XMLHttpRequest();
+          xhr.open('GET', url, true);
+          xhr.onload = function (e) {
+            let result;
+            try {
+              result = JSON.parse(e.target.responseText);
+            } catch (e) {
+              callback('获取签名出错');
+            }
+            if (result) {
+              // 使用CosAuth 利用返回的临时密钥计算签名
+              const policyInfo = CosAuth({
+                Version: 'post-object-policy', // 必传 写死 用于post签名计算
+                SecretId: result.credentials.tmpSecretId,
+                SecretKey: result.credentials.tmpSecretKey,
+                Bucket,
+                Key: opt.Key,
+              });
+              callback(null, {
+                securityToken: result.credentials.securityToken,
+                policyInfo: policyInfo,
+              });
+            } else {
+              console.error(xhr.responseText);
+              callback('获取签名出错');
+            }
+          };
+          xhr.send();
+        };
+
+        // 监听上传完成
+        let Key;
+        const submitTarget = document.getElementById('submitTarget');
+        const showMessage = function (err, data) {
+          console.log(err || data);
+          document.getElementById('msg').innerText = err
+            ? err
+            : '上传成功,ETag=' + data.ETag;
+        };
+        submitTarget.onload = function () {
+          let search;
+          try {
+            search = submitTarget.contentWindow.location.search.substr(1);
+          } catch (e) {
+            showMessage('文件 ' + Key + ' 上传失败');
+          }
+          if (search) {
+            const items = search.split('&');
+            let i = 0;
+            let arr = [];
+            const data = {};
+            for (i = 0; i < items.length; i++) {
+              arr = items[i].split('=');
+              data[arr[0]] = decodeURIComponent(arr[1] || '');
+            }
+            showMessage(null, {
+              url: prefix + camSafeUrlEncode(Key).replace(/%2F/g, '/'),
+              ETag: data.etag,
+            });
+          } else {
+          }
+        };
+
+        // 发起上传
+        document.getElementById('submitBtn').onclick = function (e) {
+          const file = document.getElementById('fileSelector').files[0];
+          if (!file) {
+            document.getElementById('msg').innerText = '未选择上传文件';
+            return;
+          }
+          Key = file.name;
+          getAuthorization({ Key }, function (err, AuthData) {
+            if (err) {
+              alert(err);
+              return;
+            }
+            // 在当前目录下放一个空的 empty.html 以便让接口上传完成跳转回来
+            document.getElementById('success_action_redirect').value =
+              location.href.substr(0, location.href.lastIndexOf('/') + 1) +
+              'empty.html';
+            document.getElementById('key').value = Key;
+            document.getElementById('policy').value =
+              AuthData.policyInfo.policy;
+            document.getElementById('q-sign-algorithm').value =
+              AuthData.policyInfo.qSignAlgorithm;
+            document.getElementById('q-ak').value = AuthData.policyInfo.qAk;
+            document.getElementById('q-key-time').value =
+              AuthData.policyInfo.qKeyTime;
+            document.getElementById('q-signature').value =
+              AuthData.policyInfo.qSignature;
+            document.getElementById('x-cos-security-token').value =
+              AuthData.securityToken || '';
+            form.submit();
+          });
+        };
+      })();
+    </script>
+  </body>
+</html>

+ 158 - 0
node_modules/cos-js-sdk-v5/demo/noSDK/post_sign.html

@@ -0,0 +1,158 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <title>Ajax Post 上传(服务端计算签名)</title>
+    <style>
+      h1,
+      h2 {
+        font-weight: normal;
+      }
+
+      #msg {
+        margin-top: 10px;
+      }
+    </style>
+  </head>
+  <body>
+    <h1>PostObject 上传(服务端计算签名)</h1>
+
+    <input id="fileSelector" type="file" />
+    <input id="submitBtn" type="submit" />
+
+    <div id="msg"></div>
+
+    <script>
+      (function () {
+        let prefix = '';
+        let Key = '';
+
+        // 对更多字符编码的 url encode 格式
+        const camSafeUrlEncode = function (str) {
+          return encodeURIComponent(str)
+            .replace(/!/g, '%21')
+            .replace(/'/g, '%27')
+            .replace(/\(/g, '%28')
+            .replace(/\)/g, '%29')
+            .replace(/\*/g, '%2A');
+        };
+
+        // 获取权限策略
+        const getAuthorization = function (opt, callback) {
+          // 替换为自己服务端地址 获取post上传签名
+          const url = `http://127.0.0.1:3000/post-policy?ext=${opt.ext}`;
+          const xhr = new XMLHttpRequest();
+          xhr.open('GET', url, true);
+          xhr.onload = function (e) {
+            let credentials;
+            try {
+              const result = JSON.parse(e.target.responseText);
+              credentials = result;
+            } catch (e) {
+              callback('获取签名出错');
+            }
+            if (credentials) {
+              callback(null, {
+                securityToken: credentials.securityToken,
+                cosKey: credentials.cosKey,
+                cosHost: credentials.cosHost,
+                policy: credentials.policy,
+                qAk: credentials.qAk,
+                qKeyTime: credentials.qKeyTime,
+                qSignAlgorithm: credentials.qSignAlgorithm,
+                qSignature: credentials.qSignature,
+              });
+            } else {
+              console.error(xhr.responseText);
+              callback('获取签名出错');
+            }
+          };
+          xhr.send();
+        };
+
+        // 上传文件
+        const uploadFile = function (file, callback) {
+          const fileName = file.name;
+          let ext = '';
+          const lastDotIndex = fileName.lastIndexOf('.');
+          if (lastDotIndex > -1) {
+            // 这里获取文件后缀 由服务端生成最终上传的路径
+            ext = fileName.substring(lastDotIndex + 1);
+          }
+          getAuthorization({ ext }, function (err, credentials) {
+            if (err) {
+              alert(err);
+              return;
+            }
+            const protocol =
+              location.protocol === 'https:' ? 'https:' : 'http:';
+            prefix = protocol + '//' + credentials.cosHost;
+            Key = credentials.cosKey;
+            const fd = new FormData();
+
+            // 在当前目录下放一个空的 empty.html 以便让接口上传完成跳转回来
+            fd.append('key', Key);
+
+            // 使用 policy 签名保护格式
+            credentials.securityToken &&
+              fd.append('x-cos-security-token', credentials.securityToken);
+            fd.append('q-sign-algorithm', credentials.qSignAlgorithm);
+            fd.append('q-ak', credentials.qAk);
+            fd.append('q-key-time', credentials.qKeyTime);
+            fd.append('q-signature', credentials.qSignature);
+            fd.append('policy', credentials.policy);
+
+            // 文件内容,file 字段放在表单最后,避免文件内容过长影响签名判断和鉴权
+            fd.append('file', file);
+
+            // xhr
+            const url = prefix;
+            const xhr = new XMLHttpRequest();
+            xhr.open('POST', url, true);
+            xhr.upload.onprogress = function (e) {
+              console.log(
+                '上传进度 ' +
+                  Math.round((e.loaded / e.total) * 10000) / 100 +
+                  '%'
+              );
+            };
+            xhr.onload = function () {
+              if (Math.floor(xhr.status / 100) === 2) {
+                const ETag = xhr.getResponseHeader('etag');
+                callback(null, {
+                  url:
+                    prefix + '/' + camSafeUrlEncode(Key).replace(/%2F/g, '/'),
+                  ETag: ETag,
+                });
+              } else {
+                callback('文件 ' + Key + ' 上传失败,状态码:' + xhr.status);
+              }
+            };
+            xhr.onerror = function () {
+              callback(
+                '文件 ' + Key + ' 上传失败,请检查是否没配置 CORS 跨域规则'
+              );
+            };
+            xhr.send(fd);
+          });
+        };
+
+        // 监听表单提交
+        document.getElementById('submitBtn').onclick = function (e) {
+          const file = document.getElementById('fileSelector').files[0];
+          if (!file) {
+            document.getElementById('msg').innerText = '未选择上传文件';
+            return;
+          }
+          file &&
+            uploadFile(file, function (err, data) {
+              console.log(err || data);
+              document.getElementById('msg').innerText = err
+                ? err
+                : '上传成功,ETag=' + data.ETag + 'url=' + data.url;
+            });
+        };
+      })();
+    </script>
+  </body>
+</html>

+ 158 - 0
node_modules/cos-js-sdk-v5/demo/noSDK/post_sts.html

@@ -0,0 +1,158 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <title>Ajax Post 上传(前端计算签名)</title>
+    <style>
+      h1,
+      h2 {
+        font-weight: normal;
+      }
+
+      #msg {
+        margin-top: 10px;
+      }
+    </style>
+  </head>
+  <body>
+    <h1>PostObject 上传(前端计算签名)</h1>
+
+    <input id="fileSelector" type="file" />
+    <input id="submitBtn" type="submit" />
+
+    <div id="msg"></div>
+
+    <!-- 签名计算 可通过(https://unpkg.com/cos-js-sdk-v5/demo/common/cos-auth.min.js)下载 -->
+    <script src="../common/cos-auth.js"></script>
+    <script>
+      (function () {
+        // 请求用到的参数
+        const Bucket = 'examplebucket-1250000000'; // 替换为自己的存储桶
+        const Region = 'ap-beijing'; // 替换为自己的存储桶地域
+        const protocol = location.protocol === 'https:' ? 'https:' : 'http:';
+        const prefix =
+          protocol + '//' + Bucket + '.cos.' + Region + '.myqcloud.com'; // prefix 用于拼接请求
+
+        // 对更多字符编码的 url encode 格式
+        const camSafeUrlEncode = function (str) {
+          return encodeURIComponent(str)
+            .replace(/!/g, '%21')
+            .replace(/'/g, '%27')
+            .replace(/\(/g, '%28')
+            .replace(/\)/g, '%29')
+            .replace(/\*/g, '%2A');
+        };
+
+        // 获取权限策略
+        const getAuthorization = function (opt, callback) {
+          // 替换为自己服务端地址 获取临时密钥
+          const url = `http://127.0.0.1:3000/sts`;
+          const xhr = new XMLHttpRequest();
+          xhr.open('GET', url, true);
+          xhr.onload = function (e) {
+            let result;
+            try {
+              result = JSON.parse(e.target.responseText);
+            } catch (e) {
+              callback('获取签名出错');
+            }
+            if (result) {
+              // 使用CosAuth利用返回的临时密钥计算签名
+              const policyInfo = CosAuth({
+                Version: 'post-object-policy', // 必传 写死 用于post签名计算
+                SecretId: result.credentials.tmpSecretId,
+                SecretKey: result.credentials.tmpSecretKey,
+                Bucket,
+                Key: opt.Key,
+              });
+              callback(null, {
+                securityToken: result.credentials.securityToken,
+                policyInfo: policyInfo,
+              });
+            } else {
+              console.error(xhr.responseText);
+              callback('获取签名出错');
+            }
+          };
+          xhr.send();
+        };
+
+        // 上传文件
+        const uploadFile = function (file, callback) {
+          const Key = file.name;
+          getAuthorization({ Key }, function (err, credentials) {
+            if (err) {
+              alert(err);
+              return;
+            }
+            const fd = new FormData();
+
+            // 在当前目录下放一个空的 empty.html 以便让接口上传完成跳转回来
+            fd.append('key', Key);
+
+            // 使用 policy 签名保护格式
+            credentials.securityToken &&
+              fd.append('x-cos-security-token', credentials.securityToken);
+            fd.append(
+              'q-sign-algorithm',
+              credentials.policyInfo.qSignAlgorithm
+            );
+            fd.append('q-ak', credentials.policyInfo.qAk);
+            fd.append('q-key-time', credentials.policyInfo.qKeyTime);
+            fd.append('q-signature', credentials.policyInfo.qSignature);
+            fd.append('policy', credentials.policyInfo.policy);
+
+            // 文件内容,file 字段放在表单最后,避免文件内容过长影响签名判断和鉴权
+            fd.append('file', file);
+
+            // xhr
+            const url = prefix;
+            const xhr = new XMLHttpRequest();
+            xhr.open('POST', url, true);
+            xhr.upload.onprogress = function (e) {
+              console.log(
+                '上传进度 ' +
+                  Math.round((e.loaded / e.total) * 10000) / 100 +
+                  '%'
+              );
+            };
+            xhr.onload = function () {
+              if (Math.floor(xhr.status / 100) === 2) {
+                const ETag = xhr.getResponseHeader('etag');
+                callback(null, {
+                  url:
+                    prefix + '/' + camSafeUrlEncode(Key).replace(/%2F/g, '/'),
+                  ETag: ETag,
+                });
+              } else {
+                callback('文件 ' + Key + ' 上传失败,状态码:' + xhr.status);
+              }
+            };
+            xhr.onerror = function () {
+              callback(
+                '文件 ' + Key + ' 上传失败,请检查是否没配置 CORS 跨域规则'
+              );
+            };
+            xhr.send(fd);
+          });
+        };
+
+        // 监听表单提交
+        document.getElementById('submitBtn').onclick = function (e) {
+          const file = document.getElementById('fileSelector').files[0];
+          if (!file) {
+            document.getElementById('msg').innerText = '未选择上传文件';
+            return;
+          }
+          file &&
+            uploadFile(file, function (err, data) {
+              console.log(err || data);
+              document.getElementById('msg').innerText = err
+                ? err
+                : '上传成功,ETag=' + data.ETag + 'url=' + data.url;
+            });
+        };
+      })();
+    </script>
+  </body>
+</html>

+ 138 - 0
node_modules/cos-js-sdk-v5/demo/noSDK/put_sign.html

@@ -0,0 +1,138 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <title>Ajax Put 上传(服务端计算签名)</title>
+    <style>
+      h1,
+      h2 {
+        font-weight: normal;
+      }
+
+      #msg {
+        margin-top: 10px;
+      }
+    </style>
+  </head>
+  <body>
+    <h1>Ajax Put 上传(服务端计算签名)</h1>
+
+    <input id="fileSelector" type="file" />
+    <input id="submitBtn" type="submit" />
+
+    <div id="msg"></div>
+
+    <script>
+      (function () {
+        // 对更多字符编码的 url encode 格式
+        const camSafeUrlEncode = function (str) {
+          return encodeURIComponent(str)
+            .replace(/!/g, '%21')
+            .replace(/'/g, '%27')
+            .replace(/\(/g, '%28')
+            .replace(/\)/g, '%29')
+            .replace(/\*/g, '%2A');
+        };
+
+        // 计算签名
+        const getAuthorization = function (opt, callback) {
+          // 替换为自己服务端地址 获取put上传签名
+          const url = `http://127.0.0.1:3000/put-sign?ext=${opt.ext}`;
+          const xhr = new XMLHttpRequest();
+          xhr.open('GET', url, true);
+          xhr.onload = function (e) {
+            let credentials;
+            try {
+              const result = JSON.parse(e.target.responseText);
+              credentials = result;
+            } catch (e) {
+              callback('获取签名出错');
+            }
+            if (credentials) {
+              callback(null, {
+                securityToken: credentials.securityToken,
+                authorization: credentials.authorization,
+                cosKey: credentials.cosKey,
+                cosHost: credentials.cosHost,
+              });
+            } else {
+              console.error(xhr.responseText);
+              callback('获取签名出错');
+            }
+          };
+          xhr.onerror = function (e) {
+            callback('获取签名出错');
+          };
+          xhr.send();
+        };
+
+        // 上传文件
+        const uploadFile = function (file, callback) {
+          const fileName = file.name;
+          let ext = '';
+          const lastDotIndex = fileName.lastIndexOf('.');
+          if (lastDotIndex > -1) {
+            // 这里获取文件后缀 由服务端生成最终上传的路径
+            ext = fileName.substring(lastDotIndex + 1);
+          }
+          getAuthorization({ ext }, function (err, info) {
+            if (err) {
+              alert(err);
+              return;
+            }
+            const auth = info.authorization;
+            const securityToken = info.securityToken;
+            const Key = info.cosKey;
+            const protocol =
+              location.protocol === 'https:' ? 'https:' : 'http:';
+            const prefix = protocol + '//' + info.cosHost;
+            const url =
+              prefix + '/' + camSafeUrlEncode(Key).replace(/%2F/g, '/');
+            const xhr = new XMLHttpRequest();
+            xhr.open('PUT', url, true);
+            xhr.setRequestHeader('Authorization', auth);
+            securityToken &&
+              xhr.setRequestHeader('x-cos-security-token', securityToken);
+            xhr.upload.onprogress = function (e) {
+              console.log(
+                '上传进度 ' +
+                  Math.round((e.loaded / e.total) * 10000) / 100 +
+                  '%'
+              );
+            };
+            xhr.onload = function () {
+              if (/^2\d\d$/.test('' + xhr.status)) {
+                const ETag = xhr.getResponseHeader('etag');
+                callback(null, { url: url, ETag: ETag });
+              } else {
+                callback('文件 ' + Key + ' 上传失败,状态码:' + xhr.status);
+              }
+            };
+            xhr.onerror = function () {
+              callback(
+                '文件 ' + Key + ' 上传失败,请检查是否没配置 CORS 跨域规则'
+              );
+            };
+            xhr.send(file);
+          });
+        };
+
+        // 监听表单提交
+        document.getElementById('submitBtn').onclick = function (e) {
+          const file = document.getElementById('fileSelector').files[0];
+          if (!file) {
+            document.getElementById('msg').innerText = '未选择上传文件';
+            return;
+          }
+          file &&
+            uploadFile(file, function (err, data) {
+              console.log(err || data);
+              document.getElementById('msg').innerText = err
+                ? err
+                : '上传成功,ETag=' + data.ETag;
+            });
+        };
+      })();
+    </script>
+  </body>
+</html>

+ 144 - 0
node_modules/cos-js-sdk-v5/demo/noSDK/put_sts.html

@@ -0,0 +1,144 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <title>Ajax Put 上传(前端计算签名)</title>
+    <style>
+      h1,
+      h2 {
+        font-weight: normal;
+      }
+
+      #msg {
+        margin-top: 10px;
+      }
+    </style>
+  </head>
+  <body>
+    <h1>Ajax Put 上传(前端计算签名)</h1>
+
+    <input id="fileSelector" type="file" />
+    <input id="submitBtn" type="submit" />
+
+    <div id="msg"></div>
+
+    <!-- 签名计算 可通过(https://unpkg.com/cos-js-sdk-v5/demo/common/cos-auth.min.js)下载 -->
+    <script src="../common/cos-auth.js"></script>
+    <script>
+      (function () {
+        // 请求用到的参数
+        const Bucket = 'test-1300555317'; // 替换为自己的存储桶
+        const Region = 'ap-beijing'; // 替换为自己的存储桶地域
+        const protocol = location.protocol === 'https:' ? 'https:' : 'http:';
+        const prefix =
+          protocol + '//' + Bucket + '.cos.' + Region + '.myqcloud.com'; // prefix 用于拼接请求
+
+        // 对更多字符编码的 url encode 格式
+        const camSafeUrlEncode = function (str) {
+          return encodeURIComponent(str)
+            .replace(/!/g, '%21')
+            .replace(/'/g, '%27')
+            .replace(/\(/g, '%28')
+            .replace(/\)/g, '%29')
+            .replace(/\*/g, '%2A');
+        };
+
+        // 计算签名
+        const getAuthorization = function (opt, callback) {
+          // 替换为自己服务端地址 获取临时密钥
+          const url = `http://127.0.0.1:3000/sts`;
+          const xhr = new XMLHttpRequest();
+          xhr.open('GET', url, true);
+          xhr.onload = function (e) {
+            let result;
+            try {
+              result = JSON.parse(e.target.responseText);
+            } catch (e) {
+              callback('获取签名出错');
+            }
+            if (result) {
+              // 使用CosAuth 利用返回的临时密钥计算签名
+              const authorization = CosAuth({
+                  SecretId: result.credentials.tmpSecretId,
+                  SecretKey: result.credentials.tmpSecretKey,
+                  Method: opt.Method,
+                  Pathname: opt.Pathname,
+              });
+              callback(null, {
+                securityToken: result.credentials.securityToken,
+                authorization: authorization,
+              });
+            } else {
+              console.error(xhr.responseText);
+              callback('获取签名出错');
+            }
+          };
+          xhr.onerror = function (e) {
+            callback('获取签名出错');
+          };
+          xhr.send();
+        };
+
+        // 上传文件
+        const uploadFile = function (file, callback) {
+          const Key = file.name;
+          getAuthorization(
+            { Method: 'PUT', Pathname: '/' + Key },
+            function (err, info) {
+              if (err) {
+                alert(err);
+                return;
+              }
+              const auth = info.authorization;
+              const securityToken = info.securityToken;
+              const url =
+                prefix + '/' + camSafeUrlEncode(Key).replace(/%2F/g, '/');
+              const xhr = new XMLHttpRequest();
+              xhr.open('PUT', url, true);
+              xhr.setRequestHeader('authorization', auth);
+              securityToken &&
+                xhr.setRequestHeader('x-cos-security-token', securityToken);
+              xhr.upload.onprogress = function (e) {
+                console.log(
+                  '上传进度 ' +
+                    Math.round((e.loaded / e.total) * 10000) / 100 +
+                    '%'
+                );
+              };
+              xhr.onload = function () {
+                if (/^2\d\d$/.test('' + xhr.status)) {
+                  const ETag = xhr.getResponseHeader('etag');
+                  callback(null, { url: url, ETag: ETag });
+                } else {
+                  callback('文件 ' + Key + ' 上传失败,状态码:' + xhr.status);
+                }
+              };
+              xhr.onerror = function () {
+                callback(
+                  '文件 ' + Key + ' 上传失败,请检查是否没配置 CORS 跨域规则'
+                );
+              };
+              xhr.send(file);
+            }
+          );
+        };
+
+        // 监听表单提交
+        document.getElementById('submitBtn').onclick = function (e) {
+          const file = document.getElementById('fileSelector').files[0];
+          if (!file) {
+            document.getElementById('msg').innerText = '未选择上传文件';
+            return;
+          }
+          file &&
+            uploadFile(file, function (err, data) {
+              console.log(err || data);
+              document.getElementById('msg').innerText = err
+                ? err
+                : '上传成功,ETag=' + data.ETag + 'url=' + data.url;
+            });
+        };
+      })();
+    </script>
+  </body>
+</html>

+ 144 - 0
node_modules/cos-js-sdk-v5/demo/policy-form.html

@@ -0,0 +1,144 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Form 表单简单上传</title>
+    <style>h1, h2 {font-weight: normal;}#msg {margin-top:10px;}</style>
+</head>
+<body>
+
+<h1>PostObject 上传(Policy 保护,Form 表单上传)</h1>
+<div>最低兼容到 IE6 上传,使用 policy 签名保护,不支持 onprogress</div>
+
+<form id="form" target="submitTarget" action="" method="post" enctype="multipart/form-data" accept="*/*">
+    <!-- file 字段放在表单最后,避免文件内容过长影响签名判断和鉴权 -->
+    <input id="fileSelector" name="file" type="file">
+    <input id="submitBtn" type="button" value="提交">
+</form>
+<iframe id="submitTarget" name="submitTarget" style="display:none;" frameborder="0"></iframe>
+
+<div id="msg"></div>
+
+<script src="common/cos-auth.min.js"></script>
+<script>
+    (function () {
+        // 请求用到的参数
+        var Bucket = 'test-1250000000';
+        var Region = 'ap-guangzhou';
+        var protocol = location.protocol === 'https:' ? 'https:' : 'http:';
+        var prefix = protocol + '//' + Bucket + '.cos.' + Region + '.myqcloud.com/';
+        var fileSelector = document.getElementById('fileSelector');
+        var form = document.getElementById('form');
+        form.action = prefix;
+
+        // 对更多字符编码的 url encode 格式
+        var camSafeUrlEncode = function (str) {
+            return encodeURIComponent(str)
+                .replace(/!/g, '%21')
+                .replace(/'/g, '%27')
+                .replace(/\(/g, '%28')
+                .replace(/\)/g, '%29')
+                .replace(/\*/g, '%2A');
+        };
+
+        // 获取权限策略
+        var getPostPolicyCredentials = function (opt, callback) {
+            var url = 'http://127.0.0.1:3000/post-policy?key=' + encodeURIComponent(opt.Key);
+            var xhr = new XMLHttpRequest();
+            xhr.open('GET', url, true);
+            xhr.onreadystatechange = function (e) {
+                if (xhr.readyState === 4) {
+                    if (xhr.status === 200) {
+                        var credentials;
+                        try {
+                            credentials = (new Function('return ' + xhr.responseText))();
+                        } catch (e) {}
+                        if (credentials) {
+                            callback(null, credentials);
+                        } else {
+                            console.error(xhr.responseText);
+                            callback('获取签名出错');
+                        }
+                    } else {
+                        callback('获取签名出错');
+                    }
+                }
+            };
+            xhr.send();
+        };
+
+        // 监听上传完成
+        var Key;
+        var submitTarget = document.getElementById('submitTarget');
+        var showMessage = function (err, data) {
+            console.log(err || data);
+            document.getElementById('msg').innerText = err ? err : ('上传成功,ETag=' + data.ETag);
+        };
+        submitTarget.onload = function () {
+            var search;
+            try {
+                search = submitTarget.contentWindow.location.search.substr(1);
+            } catch (e) {
+                showMessage('文件 ' + Key + ' 上传失败');
+            }
+            if (search) {
+                var items = search.split('&');
+                var i, arr, data = {};
+                for (i = 0; i < items.length; i++) {
+                    arr = items[i].split('=');
+                    data[arr[0]] = decodeURIComponent(arr[1] || '');
+                }
+                showMessage(null, {url: prefix + camSafeUrlEncode(Key).replace(/%2F/g, '/'), ETag: data.etag});
+            } else {
+            }
+        };
+
+        var setFormField = function (key, value) {
+            var el = document.getElementById(key);
+            if (!el) {
+                el = document.createElement('input');
+                el.hidden = true;
+                el.id = key;
+                el.name = key;
+                form.insertBefore(el, fileSelector);
+            }
+            el.setAttribute('value', value); // 需要保证 file 在表单最后
+            el.value = value;
+        };
+
+        // 发起上传
+        document.getElementById('submitBtn').onclick = function (e) {
+            var filePath = document.getElementById('fileSelector').value;
+            if (!filePath) {
+                document.getElementById('msg').innerText = '未选择上传文件';
+                return;
+            }
+            Key = 'dir/' + filePath.match(/[\\\/]?([^\\\/]+)$/)[1]; // 这里指定上传目录和文件名
+
+            // 获取签名保护字段
+            getPostPolicyCredentials({
+                Key: Key,
+            }, function (err, credentials) {
+
+                // 在当前目录下放一个空的 empty.html 以便让接口上传完成跳转回来
+                setFormField('success_action_redirect', location.href.substr(0, location.href.lastIndexOf('/') + 1) + 'empty.html');
+                setFormField('key', Key);
+
+                // 使用 policy 签名保护格式
+                credentials.securityToken && setFormField('x-cos-security-token', credentials.securityToken);
+                setFormField('q-sign-algorithm', credentials.qSignAlgorithm);
+                setFormField('q-ak', credentials.qAk);
+                setFormField('q-key-time', credentials.qKeyTime);
+                setFormField('q-signature', credentials.qSignature);
+                setFormField('policy', credentials.policy);
+
+                // 提交表单
+                form.submit();
+
+            });
+        };
+    })();
+</script>
+
+</body>
+</html>

+ 137 - 0
node_modules/cos-js-sdk-v5/demo/policy-post.html

@@ -0,0 +1,137 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Ajax Post 上传</title>
+    <style>
+        h1, h2 {
+            font-weight: normal;
+        }
+
+        #msg {
+            margin-top: 10px;
+        }
+    </style>
+</head>
+<body>
+
+<h1>PostObject 上传(Policy 保护,Ajax POST 请求)</h1>
+
+<input id="fileSelector" type="file">
+<input id="submitBtn" type="submit">
+
+<div id="msg"></div>
+
+<script src="common/cos-auth.min.js"></script>
+<script>
+    (function () {
+
+        // 请求用到的参数
+        var Bucket = 'test-1250000000';
+        var Region = 'ap-guangzhou';
+        var protocol = location.protocol === 'https:' ? 'https:' : 'http:';
+        var prefix = protocol + '//' + Bucket + '.cos.' + Region + '.myqcloud.com/';
+
+        // 对更多字符编码的 url encode 格式
+        var camSafeUrlEncode = function (str) {
+            return encodeURIComponent(str)
+                .replace(/!/g, '%21')
+                .replace(/'/g, '%27')
+                .replace(/\(/g, '%28')
+                .replace(/\)/g, '%29')
+                .replace(/\*/g, '%2A');
+        };
+
+        // 获取权限策略
+        var getPostPolicyCredentials = function (opt, callback) {
+            var url = 'http://127.0.0.1:3000/post-policy?key=' + encodeURIComponent(opt.Key);
+            var xhr = new XMLHttpRequest();
+            xhr.open('GET', url, true);
+            xhr.onreadystatechange = function (e) {
+                if (xhr.readyState === 4) {
+                    if (xhr.status === 200) {
+                        var credentials;
+                        try {
+                            credentials = (new Function('return ' + xhr.responseText))();
+                        } catch (e) {}
+                        if (credentials) {
+                            callback(null, credentials);
+                        } else {
+                            console.error(xhr.responseText);
+                            callback('获取签名出错');
+                        }
+                    } else {
+                        callback('获取签名出错');
+                    }
+                }
+            };
+            xhr.send();
+        };
+
+        // 上传文件
+        var uploadFile = function (file, callback) {
+            var Key = 'dir/' + file.name; // 这里指定上传目录和文件名
+            getPostPolicyCredentials({
+                Bucket: Bucket,
+                Key: Key,
+                ACL: 'default'
+            }, function (err, credentials) {
+                var fd = new FormData();
+
+                // 在当前目录下放一个空的 empty.html 以便让接口上传完成跳转回来
+                fd.append('key', Key);
+
+                // // 使用普通签名格式
+                // fd.append('Signature', credentials.Authorization);
+                // fd.append('x-cos-security-token', credentials.SecurityToken || '');
+
+                // 使用 policy 签名保护格式
+                credentials.securityToken && fd.append('x-cos-security-token', credentials.securityToken);
+                fd.append('q-sign-algorithm', credentials.qSignAlgorithm);
+                fd.append('q-ak', credentials.qAk);
+                fd.append('q-key-time', credentials.qKeyTime);
+                fd.append('q-signature', credentials.qSignature);
+                fd.append('policy', credentials.policy);
+
+                // 文件内容,file 字段放在表单最后,避免文件内容过长影响签名判断和鉴权
+                fd.append('file', file);
+
+                // xhr
+                var url = prefix;
+                var xhr = new XMLHttpRequest();
+                xhr.open('POST', url, true);
+                xhr.upload.onprogress = function (e) {
+                    console.log('上传进度 ' + (Math.round(e.loaded / e.total * 10000) / 100) + '%');
+                };
+                xhr.onload = function () {
+                    if (Math.floor(xhr.status / 100) === 2) {
+                        var ETag = xhr.getResponseHeader('etag');
+                        callback(null, {url: prefix + camSafeUrlEncode(Key).replace(/%2F/g, '/'), ETag: ETag});
+                    } else {
+                        callback('文件 ' + Key + ' 上传失败,状态码:' + xhr.status);
+                    }
+                };
+                xhr.onerror = function () {
+                    callback('文件 ' + Key + ' 上传失败,请检查是否没配置 CORS 跨域规则');
+                };
+                xhr.send(fd);
+            });
+        };
+
+        // 监听表单提交
+        document.getElementById('submitBtn').onclick = function (e) {
+            var file = document.getElementById('fileSelector').files[0];
+            if (!file) {
+                document.getElementById('msg').innerText = '未选择上传文件';
+                return;
+            }
+            file && uploadFile(file, function (err, data) {
+                console.log(err || data);
+                document.getElementById('msg').innerText = err ? err : ('上传成功,ETag=' + data.ETag);
+            });
+        };
+    })();
+</script>
+
+</body>
+</html>

+ 193 - 0
node_modules/cos-js-sdk-v5/demo/post_sign.html

@@ -0,0 +1,193 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <title>Form 表单简单上传</title>
+    <style>
+      h1,
+      h2 {
+        font-weight: normal;
+      }
+      #msg {
+        margin-top: 10px;
+      }
+    </style>
+  </head>
+  <body>
+    <h1>Form 表单简单上传(兼容 IE8)</h1>
+    <div>最低兼容到 IE6 上传,不支持 onprogress</div>
+
+    <form
+      id="form"
+      target="submitTarget"
+      action=""
+      method="post"
+      enctype="multipart/form-data"
+      accept="*/*"
+    >
+      <input id="name" name="name" type="hidden" value="" />
+      <input name="success_action_status" type="hidden" value="200" />
+      <input
+        id="success_action_redirect"
+        name="success_action_redirect"
+        type="hidden"
+        value=""
+      />
+      <input id="key" name="key" type="hidden" value="" />
+      <input id="policy" name="policy" type="hidden" value="" />
+      <input
+        id="q-sign-algorithm"
+        name="q-sign-algorithm"
+        type="hidden"
+        value=""
+      />
+      <input id="q-ak" name="q-ak" type="hidden" value="" />
+      <input id="q-key-time" name="q-key-time" type="hidden" value="" />
+      <input id="q-signature" name="q-signature" type="hidden" value="" />
+      <input name="Content-Type" type="hidden" value="" />
+      <input
+        id="x-cos-security-token"
+        name="x-cos-security-token"
+        type="hidden"
+        value=""
+      />
+
+      <!-- file 字段放在表单最后,避免文件内容过长影响签名判断和鉴权 -->
+      <input id="fileSelector" name="file" type="file" />
+      <input id="submitBtn" type="button" value="提交" />
+    </form>
+    <iframe
+      id="submitTarget"
+      name="submitTarget"
+      style="display: none"
+      frameborder="0"
+    ></iframe>
+
+    <div id="msg"></div>
+
+    <script>
+      (function () {
+        const form = document.getElementById('form');
+        let prefix = '';
+
+        // 对更多字符编码的 url encode 格式
+        const camSafeUrlEncode = function (str) {
+          return encodeURIComponent(str)
+            .replace(/!/g, '%21')
+            .replace(/'/g, '%27')
+            .replace(/\(/g, '%28')
+            .replace(/\)/g, '%29')
+            .replace(/\*/g, '%2A');
+        };
+
+        // 计算签名
+        const getAuthorization = function (options, callback) {
+          // 替换为自己服务端地址 获取post上传签名
+          const url = `http://127.0.0.1:3000/post-policy?ext=${options.ext}`;
+          const xhr = new XMLHttpRequest();
+          xhr.open('GET', url, true);
+          xhr.onreadystatechange = function (e) {
+            if (xhr.readyState === 4) {
+              if (/^2\d\d$/.test('' + xhr.status)) {
+                let credentials;
+                try {
+                  const result = JSON.parse(e.target.responseText);
+                  credentials = result;
+                } catch (e) {
+                  callback('获取签名出错');
+                }
+                if (credentials) {
+                  callback(null, {
+                    SecurityToken: credentials.sessionToken,
+                    cosKey: credentials.cosKey,
+                    cosHost: credentials.cosHost,
+                    policy: credentials.policy,
+                    qAk: credentials.qAk,
+                    qKeyTime: credentials.qKeyTime,
+                    qSignAlgorithm: credentials.qSignAlgorithm,
+                    qSignature: credentials.qSignature,
+                  });
+                } else {
+                  console.error(xhr.responseText);
+                  callback('获取签名出错');
+                }
+              } else {
+                callback('获取签名出错');
+              }
+            }
+          };
+          xhr.send();
+        };
+
+        // 监听上传完成
+        let Key;
+        const submitTarget = document.getElementById('submitTarget');
+        const showMessage = function (err, data) {
+          console.log(err || data);
+          document.getElementById('msg').innerText = err
+            ? err
+            : '上传成功,ETag=' + data.ETag;
+        };
+        submitTarget.onload = function () {
+          let search;
+          try {
+            search = submitTarget.contentWindow.location.search.substr(1);
+          } catch (e) {
+            showMessage('文件 ' + Key + ' 上传失败');
+          }
+          if (search) {
+            const items = search.split('&');
+            let i = 0;
+            let arr = [];
+            const data = {};
+            for (i = 0; i < items.length; i++) {
+              arr = items[i].split('=');
+              data[arr[0]] = decodeURIComponent(arr[1] || '');
+            }
+            showMessage(null, {
+              url: prefix + camSafeUrlEncode(Key).replace(/%2F/g, '/'),
+              ETag: data.etag,
+            });
+          } else {
+          }
+        };
+
+        // 发起上传
+        document.getElementById('submitBtn').onclick = function (e) {
+          const filePath = document.getElementById('fileSelector').value;
+          if (!filePath) {
+            document.getElementById('msg').innerText = '未选择上传文件';
+            return;
+          }
+          let ext = '';
+          const lastDotIndex = filePath.lastIndexOf('.');
+          if (lastDotIndex > -1) {
+            // 这里获取文件后缀 由服务端生成最终上传的路径
+            const ext = filePath.substring(lastDotIndex + 1);
+          }
+          getAuthorization({ ext }, function (err, AuthData) {
+            const protocol =
+              location.protocol === 'https:' ? 'https:' : 'http:';
+            prefix = protocol + '//' + AuthData.cosHost;
+            form.action = prefix;
+            Key = AuthData.cosKey;
+            // 在当前目录下放一个空的 empty.html 以便让接口上传完成跳转回来
+            document.getElementById('success_action_redirect').value =
+              location.href.substr(0, location.href.lastIndexOf('/') + 1) +
+              'empty.html';
+            document.getElementById('key').value = AuthData.cosKey;
+            document.getElementById('policy').value = AuthData.policy;
+            document.getElementById('q-sign-algorithm').value =
+              AuthData.qSignAlgorithm;
+            document.getElementById('q-ak').value = AuthData.qAk;
+            document.getElementById('q-key-time').value = AuthData.qKeyTime;
+            document.getElementById('q-signature').value = AuthData.qSignature;
+            document.getElementById('x-cos-security-token').value =
+              AuthData.SecurityToken || '';
+            form.submit();
+          });
+        };
+      })();
+    </script>
+  </body>
+</html>

+ 66 - 0
node_modules/cos-js-sdk-v5/demo/queue/index.html

@@ -0,0 +1,66 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport"
+          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
+    <meta http-equiv="X-UA-Compatible" content="ie=edge">
+    <title>COS 上传队列</title>
+    <link rel="stylesheet" href="style.css">
+</head>
+<body>
+
+<div class="page">
+    <h1>COS 上传队列</h1>
+    <div id="app">
+        <form id="form">
+            <div class="float-right">共{{total}}个文件</div>
+            <input type="file" value="选择上传文件" multiple @change="selectedFile">
+        </form>
+        <table class="file-list">
+            <colgroup>
+                <col style="width:20%;">
+                <col style="width:10%;">
+                <col style="width:40%;">
+                <col style="width:30%;">
+            </colgroup>
+            <tr class="file-item">
+                <td>文件名</td>
+                <td>大小</td>
+                <td>进度</td>
+                <td class="file-action">操作</td>
+            </tr>
+            <tr class="file-item" v-for="item in list">
+                <td><span class="file-name">{{item.Key}}</span></td>
+                <td>{{formatSize(item.size)}}</td>
+                <td>
+                    <span class="file-progress" v-if="item.state==='uploading'">
+                        <span class="file-progress-loaded" :style="'width:'+item.percent*100+'%'"></span>
+                    </span>
+                    <span v-if="item.state==='success'">已完成</span>
+                    <span v-else-if="item.state==='waiting'">等待上传</span>
+                    <span v-else-if="item.state==='checking'">校验中({{parseInt(item.hashPercent*100)}}%)</span>
+                    <span v-else-if="item.state==='paused'">已暂停, 已传{{formatSize(item.loaded)}}</span>
+                    <span v-else-if="item.state==='canceled'">已取消</span>
+                    <span v-else>{{formatSize(item.speed)}}/s, 已传{{formatSize(item.loaded)}} {{parseInt(item.percent*100)}}%</span>
+                </td>
+                <td class="file-action">
+                    <a v-if="['waiting','checking','uploading'].includes(item.state)" href="javascript:void(0)" @click="pauseTask(item)">暂停</a>
+                    <a v-if="['error','paused'].includes(item.state)" href="javascript:void(0)" @click="restartTask(item)">开始</a>
+                    <a v-if="item.state!=='canceled'" href="javascript:void(0)" @click="cancelTask(item)">删除</a>
+                </td>
+            </tr>
+            <tr class="file-item" v-if="!list.length">
+                <td colspan="4" align="center">暂无上传文件</td>
+            </tr>
+        </table>
+    </div>
+</div>
+
+<script src="../../dist/cos-js-sdk-v5.js"></script>
+<script src="../common/lodash.core.min.js"></script>
+<script src="../common/vue.min.js"></script>
+<script src="./index.js"></script>
+
+</body>
+</html>

+ 77 - 0
node_modules/cos-js-sdk-v5/demo/queue/index.js

@@ -0,0 +1,77 @@
+var Bucket = 'test-1250000000';
+var Region = 'ap-guangzhou';
+
+var cos = new COS({
+    FileParallelLimit: 5,
+    ChunkParallelLimit: 5,
+    ChunkMbSize: 8 * 1024 * 1024,
+    getAuthorization: function (options, callback) {
+        var url = '/sts';
+        var xhr = new XMLHttpRequest();
+        xhr.open('GET', url, true);
+        xhr.onload = function (e) {
+            try {
+                var data = JSON.parse(e.target.responseText);
+            } catch (e) {
+            }
+            callback({
+                TmpSecretId: data.credentials && data.credentials.tmpSecretId,
+                TmpSecretKey: data.credentials && data.credentials.tmpSecretKey,
+                SecurityToken: data.credentials && data.credentials.sessionToken,
+                ExpiredTime: data.expiredTime
+            });
+        };
+        xhr.send();
+    }
+});
+
+new Vue({
+    el: '#app',
+    data: function () {
+        return {
+            FileParallelLimit: 5,
+            ChunkParallelLimit: 16,
+            ChunkMbSize: 2,
+            list: [],
+            total: 0,
+        };
+    },
+    created: function () {
+        var self = this;
+        cos.on('list-update', function (data) {
+            self.list = data.list;
+            self.total = data.list.length;
+        });
+    },
+    methods: {
+        formatSize: function (size) {
+            var i, unit = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
+            for (i = 0; i < unit.length && size >= 1024; i++) {
+                size /= 1024;
+            }
+            return (Math.round(size * 100) / 100 || 0) + unit[i];
+        },
+        selectedFile: function (e) {
+            var files = e.target.files;
+            var list = [].map.call(files, function (f) {
+                return {
+                    Bucket: Bucket,
+                    Region: Region,
+                    Key: f.name,
+                    Body: f,
+                };
+            });
+            cos.uploadFiles({files: list});
+            document.getElementById('form').reset();
+        },
+        pauseTask: function (task) {
+            cos.pauseTask(task.id);
+        },
+        restartTask: function (task) {
+            cos.restartTask(task.id);
+        },
+        cancelTask: function (task) {
+            cos.cancelTask(task.id);
+        },
+    },
+});

+ 78 - 0
node_modules/cos-js-sdk-v5/demo/queue/style.css

@@ -0,0 +1,78 @@
+h1 {
+    font-family: "Microsoft YaHei";
+    font-weight: normal;
+}
+
+ul,
+li {
+    list-style: none;
+    margin: 0;
+    padding: 0;
+}
+
+a {
+    color: #0071ff;
+}
+
+.float-right {
+    float: right;
+}
+
+.page {
+    width: 960px;
+    margin: 0 auto;
+    font-size: 14px;
+}
+
+#form input[type="text"] {
+    width: 40px;
+    padding: 2px;
+    vertical-align: middle;
+}
+#form input[type="file"] {
+    vertical-align: middle;
+}
+
+.file-list {
+    margin-top: 20px;
+    width: 100%;
+}
+
+.file-list {
+    width: 960px;
+    border-collapse: collapse;
+}
+
+.file-name {
+    display: inline-block;
+    width: 310px;
+    text-overflow: ellipsis;
+    white-space: nowrap
+}
+
+.file-item td {
+    border: 1px solid #ccc;
+    padding: 5px 10px;
+    font-size: 12px;
+    line-height: 20px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap
+}
+
+.file-progress {
+    position: relative;
+    display: inline-block;
+    width: 100px;
+    height: 6px;
+    background: #ddd;
+    vertical-align: middle;
+    margin-right: 5px;
+}
+
+.file-progress-loaded {
+    position: absolute;
+    display: inline-block;
+    height: 6px;
+    background: #0071ff;
+}

+ 170 - 0
node_modules/cos-js-sdk-v5/demo/slice-task.html

@@ -0,0 +1,170 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>自定义的分片上传</title>
+    <style>
+        h1, h2 {
+            font-weight: normal;
+        }
+
+        #msg {
+            margin-top: 10px;
+        }
+    </style>
+</head>
+<body>
+
+<h1>自定义的分片上传</h1>
+
+<input id="fileSelector" type="file">
+<input id="submitBtn" type="button" value="上传文件">
+<input id="cancelBtn" type="button" value="取消最后一个上传文件">
+
+<div id="msg"></div>
+
+<script src="../dist/cos-js-sdk-v5.js"></script>
+<script src="./common/async.js"></script>
+<script>
+    (function () {
+        // 请求用到的参数
+        var Bucket = 'test-1250000000';
+        var Region = 'ap-guangzhou';
+        var ChunkSize = 1024 * 1024 * 8;
+
+        // 初始化 SDK
+        var cos = new COS({
+            getAuthorization: function (options, callback) {
+                var url = '/sts'; // 如果是 npm run sts.js 起的 nodejs server,使用这个
+                var xhr = new XMLHttpRequest();
+                xhr.open('GET', url, true);
+                xhr.onload = function (e) {
+                    try {
+                        var data = JSON.parse(e.target.responseText);
+                        var credentials = data.credentials;
+                    } catch (e) {
+                    }
+                    if (!data || !credentials) return console.error('credentials invalid');
+                    callback({
+                        TmpSecretId: credentials.tmpSecretId,
+                        TmpSecretKey: credentials.tmpSecretKey,
+                        SecurityToken: credentials.sessionToken,
+                        StartTime: data.startTime, // 时间戳,单位秒,如:1580000000,建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
+                        ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000900
+                    });
+                };
+                xhr.send();
+            },
+        });
+        var uuid = function () {
+            var S4 = function () {
+                return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
+            };
+            return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
+        };
+
+        // 外部维护上传任务状态
+        var lastTaskId;
+        var taskStateMap = {};
+        cos._isRunningTask = function (tid) {
+            return taskStateMap[tid] === 'uploading';
+        };
+
+        // 上传文件
+        var uploadFile = function (file, callback) {
+            var TaskId = lastTaskId = uuid();
+            taskStateMap[TaskId] = 'uploading';
+            var fileSize = file.size;
+            var Key = 'dir/' + file.name; // 这里指定上传目录和文件名
+            console.log('上传任务已开始:' + lastTaskId, TaskId, Key);
+            // 创建 UploadId
+            cos.multipartInit({
+                Bucket: Bucket,
+                Region: Region,
+                Key: Key,
+            }, function (err, data) {
+                if (!cos._isRunningTask(TaskId)) return;
+                if (err) {
+                    taskStateMap[TaskId] = 'error';
+                    return console.error('UploadId 创建出错:', err);
+                }
+                var UploadId = data.UploadId;
+                console.log('UploadId 已创建:', UploadId);
+                var Parts = new Array(Math.ceil(fileSize / ChunkSize)).fill(0).map(function (item, index) {
+                    return {PartNumber: index + 1};
+                });
+                Async.eachLimit(Parts, 3, function (partItem, nextPart) {
+                    if (!cos._isRunningTask(TaskId)) return;
+                    var PartNumber = partItem.PartNumber;
+                    var start = (PartNumber - 1) * ChunkSize;
+                    var end = Math.min(start + ChunkSize);
+                    var blob = file.slice(start, end);
+                    // 上传每个分片
+                    cos.multipartUpload({
+                        Task: lastTaskId,
+                        Bucket: Bucket,
+                        Region: Region,
+                        Key: Key,
+                        UploadId: UploadId,
+                        PartNumber: PartNumber,
+                        Body: blob,
+                    }, function (err, data) {
+                        if (!cos._isRunningTask(TaskId)) return;
+                        if (err) return nextPart(err);
+                        if (!data.headers.etag) return nextPart('浏览器获取不到 ETag Header,需要存储桶配置 CORS ExposeHeaders 允许当前域名跨域读取 ETag 字段。');
+                        partItem.ETag = data.headers.etag || '';
+                        console.log('分片上传完成:', partItem.PartNumber, partItem.ETag);
+                        nextPart();
+                    });
+                }, function (err) {
+                    if (!cos._isRunningTask(TaskId)) return;
+                    if (err) {
+                        taskStateMap[TaskId] = 'error';
+                        return console.error('上传分片出错:', err);
+                    }
+                    // 完成分片上传
+                    cos.multipartComplete({
+                        Bucket: Bucket,
+                        Region: Region,
+                        Key: Key,
+                        UploadId: UploadId,
+                        Parts: Parts,
+                    }, function (err, data) {
+                        if (err) {
+                            taskStateMap[TaskId] = 'error';
+                            return console.error('文件完成出错:', err);
+                        }
+                        console.log('文件上传成功:', data.Location);
+                        taskStateMap[TaskId] = 'success';
+                        callback(err, data);
+                    });
+                });
+            });
+        };
+
+        // 监听表单提交
+        document.getElementById('submitBtn').onclick = function (e) {
+            var file = document.getElementById('fileSelector').files[0];
+            if (!file) {
+                document.getElementById('msg').innerText = '未选择上传文件';
+                return;
+            }
+            file && uploadFile(file, function (err, data) {
+                console.log(err || data);
+                document.getElementById('msg').innerText = err ? err : ('上传成功,ETag=' + data.ETag);
+            });
+        };
+
+        // 监听取消上传
+        document.getElementById('cancelBtn').onclick = function (e) {
+            // 标记任务取消,让 SDK 外部的上传流程停止
+            taskStateMap[lastTaskId] = 'canceled';
+            // 取消 SDK 正在执行的 xhr 上传请求,触发 xhr.abort()
+            cos.cancelTask(lastTaskId);
+            console.log('上传任务已取消:' + lastTaskId);
+        };
+    })();
+</script>
+
+</body>
+</html>

+ 129 - 0
node_modules/cos-js-sdk-v5/demo/slice.html

@@ -0,0 +1,129 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>自定义的分片上传</title>
+    <style>
+        h1, h2 {
+            font-weight: normal;
+        }
+
+        #msg {
+            margin-top: 10px;
+        }
+    </style>
+</head>
+<body>
+
+<h1>自定义的分片上传</h1>
+
+<input id="fileSelector" type="file">
+<input id="submitBtn" type="submit">
+
+<div id="msg"></div>
+
+<script src="../dist/cos-js-sdk-v5.js"></script>
+<script src="./common/async.js"></script>
+<script>
+    (function () {
+        // 请求用到的参数
+        var Bucket = 'test-1250000000';
+        var Region = 'ap-guangzhou';
+        var ChunkSize = 1024 * 1024 * 8;
+
+        // 初始化 SDK
+        var cos = new COS({
+            getAuthorization: function (options, callback) {
+                var url = '/sts'; // 如果是 npm run sts.js 起的 nodejs server,使用这个
+                var xhr = new XMLHttpRequest();
+                xhr.open('GET', url, true);
+                xhr.onload = function (e) {
+                    try {
+                        var data = JSON.parse(e.target.responseText);
+                        var credentials = data.credentials;
+                    } catch (e) {
+                    }
+                    if (!data || !credentials) return console.error('credentials invalid');
+                    callback({
+                        TmpSecretId: credentials.tmpSecretId,
+                        TmpSecretKey: credentials.tmpSecretKey,
+                        SecurityToken: credentials.sessionToken,
+                        StartTime: data.startTime, // 时间戳,单位秒,如:1580000000,建议返回服务器时间作为签名的开始时间,避免用户浏览器本地时间偏差过大导致签名错误
+                        ExpiredTime: data.expiredTime, // 时间戳,单位秒,如:1580000900
+                    });
+                };
+                xhr.send();
+            },
+        });
+
+        // 上传文件
+        var uploadFile = function (file, callback) {
+            var fileSize = file.size;
+            var Key = 'dir/' + file.name; // 这里指定上传目录和文件名
+            // 创建 UploadId
+            cos.multipartInit({
+                Bucket: Bucket,
+                Region: Region,
+                Key: Key,
+            }, function (err, data) {
+                if (err) return console.error('UploadId 创建出错:', err);
+                var UploadId = data.UploadId;
+                console.log('UploadId 已创建:', UploadId);
+                var Parts = new Array(Math.ceil(fileSize / ChunkSize)).fill(0).map(function (item, index) {
+                    return {PartNumber: index + 1};
+                });
+                Async.eachLimit(Parts, 3, function (partItem, nextPart) {
+                    var PartNumber = partItem.PartNumber;
+                    var start = (PartNumber - 1) * ChunkSize;
+                    var end = Math.min(start + ChunkSize);
+                    var blob = file.slice(start, end);
+                    // 上传每个分片
+                    cos.multipartUpload({
+                        Bucket: Bucket,
+                        Region: Region,
+                        Key: Key,
+                        UploadId: UploadId,
+                        PartNumber: PartNumber,
+                        Body: blob,
+                    }, function (err, data) {
+                        if (err) return nextPart(err);
+                        if (!data.headers.etag) return nextPart('浏览器获取不到 ETag Header,需要存储桶配置 CORS ExposeHeaders 允许当前域名跨域读取 ETag 字段。');
+                        partItem.ETag = data.headers.etag || '';
+                        console.log('分片上传完成:', partItem.PartNumber, partItem.ETag);
+                        nextPart();
+                    });
+                }, function (err) {
+                    if (err) return console.error('上传分片出错:', err);
+                    // 完成分片上传
+                    cos.multipartComplete({
+                        Bucket: Bucket,
+                        Region: Region,
+                        Key: Key,
+                        UploadId: UploadId,
+                        Parts: Parts,
+                    }, function (err, data) {
+                        if (err) return console.error('文件完成出错:', err);
+                        console.log('文件上传成功:', data.Location);
+                        callback(err, data);
+                    });
+                });
+            });
+        };
+
+        // 监听表单提交
+        document.getElementById('submitBtn').onclick = function (e) {
+            var file = document.getElementById('fileSelector').files[0];
+            if (!file) {
+                document.getElementById('msg').innerText = '未选择上传文件';
+                return;
+            }
+            file && uploadFile(file, function (err, data) {
+                console.log(err || data);
+                document.getElementById('msg').innerText = err ? err : ('上传成功,ETag=' + data.ETag);
+            });
+        };
+    })();
+</script>
+
+</body>
+</html>

+ 134 - 0
node_modules/cos-js-sdk-v5/demo/sts-form.html

@@ -0,0 +1,134 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Form 表单简单上传</title>
+    <style>h1, h2 {font-weight: normal;}#msg {margin-top:10px;}</style>
+</head>
+<body>
+
+<h1>Form 表单简单上传(兼容 IE8)</h1>
+<div>最低兼容到 IE6 上传,不支持 onprogress</div>
+
+<form id="form" target="submitTarget" action="" method="post" enctype="multipart/form-data" accept="*/*">
+    <input id="name" name="name" type="hidden" value="">
+    <input name="success_action_status" type="hidden" value="200">
+    <input id="success_action_redirect" name="success_action_redirect" type="hidden" value="">
+    <input id="key" name="key" type="hidden" value="">
+    <input id="Signature" name="Signature" type="hidden" value="">
+    <input name="Content-Type" type="hidden" value="">
+    <input id="x-cos-security-token" name="x-cos-security-token" type="hidden" value="">
+
+    <!-- file 字段放在表单最后,避免文件内容过长影响签名判断和鉴权 -->
+    <input id="fileSelector" name="file" type="file">
+    <input id="submitBtn" type="button" value="提交">
+</form>
+<iframe id="submitTarget" name="submitTarget" style="display:none;" frameborder="0"></iframe>
+
+<div id="msg"></div>
+
+<script src="common/cos-auth.min.js"></script>
+<script>
+    (function () {
+
+        // 请求用到的参数
+        var Bucket = 'test-1250000000';
+        var Region = 'ap-guangzhou';
+        var protocol = location.protocol === 'https:' ? 'https:' : 'http:';
+        var prefix = protocol + '//' + Bucket + '.cos.' + Region + '.myqcloud.com/';
+        var form = document.getElementById('form');
+        form.action = prefix;
+
+        // 对更多字符编码的 url encode 格式
+        var camSafeUrlEncode = function (str) {
+            return encodeURIComponent(str)
+                .replace(/!/g, '%21')
+                .replace(/'/g, '%27')
+                .replace(/\(/g, '%28')
+                .replace(/\)/g, '%29')
+                .replace(/\*/g, '%2A');
+        };
+
+        // 计算签名
+        var getAuthorization = function (options, callback) {
+            // var url = 'http://127.0.0.1:3000/sts';
+            var url = '../server/sts.php';
+            var xhr = new XMLHttpRequest();
+            xhr.open('GET', url, true);
+            xhr.onreadystatechange = function (e) {
+                if (xhr.readyState === 4) {
+                    if (xhr.status === 200) {
+                        var credentials;
+                        try {
+                            credentials = (new Function('return ' + xhr.responseText))().credentials;
+                        } catch (e) {}
+                        if (credentials) {
+                            callback(null, {
+                                SecurityToken: credentials.sessionToken,
+                                Authorization: CosAuth({
+                                    SecretId: credentials.tmpSecretId,
+                                    SecretKey: credentials.tmpSecretKey,
+                                    Method: options.Method,
+                                    Pathname: options.Pathname,
+                                })
+                            });
+                        } else {
+                            console.error(xhr.responseText);
+                            callback('获取签名出错');
+                        }
+                    } else {
+                        callback('获取签名出错');
+                    }
+                }
+            };
+            xhr.send();
+        };
+
+        // 监听上传完成
+        var Key;
+        var submitTarget = document.getElementById('submitTarget');
+        var showMessage = function (err, data) {
+            console.log(err || data);
+            document.getElementById('msg').innerText = err ? err : ('上传成功,ETag=' + data.ETag);
+        };
+        submitTarget.onload = function () {
+            var search;
+            try {
+                search = submitTarget.contentWindow.location.search.substr(1);
+            } catch (e) {
+                showMessage('文件 ' + Key + ' 上传失败');
+            }
+            if (search) {
+                var items = search.split('&');
+                var i, arr, data = {};
+                for (i = 0; i < items.length; i++) {
+                    arr = items[i].split('=');
+                    data[arr[0]] = decodeURIComponent(arr[1] || '');
+                }
+                showMessage(null, {url: prefix + camSafeUrlEncode(Key).replace(/%2F/g, '/'), ETag: data.etag});
+            } else {
+            }
+        };
+
+        // 发起上传
+        document.getElementById('submitBtn').onclick = function (e) {
+            var filePath = document.getElementById('fileSelector').value;
+            if (!filePath) {
+                document.getElementById('msg').innerText = '未选择上传文件';
+                return;
+            }
+            Key = 'dir/' + filePath.match(/[\\\/]?([^\\\/]+)$/)[1]; // 这里指定上传目录和文件名
+            getAuthorization({Method: 'POST', Pathname: '/'}, function (err, AuthData) {
+                // 在当前目录下放一个空的 empty.html 以便让接口上传完成跳转回来
+                document.getElementById('success_action_redirect').value = location.href.substr(0, location.href.lastIndexOf('/') + 1) + 'empty.html';
+                document.getElementById('key').value = Key;
+                document.getElementById('signature').value = AuthData.Authorization;
+                document.getElementById('x-cos-security-token').value = AuthData.SecurityToken || '';
+                form.submit();
+            });
+        };
+    })();
+</script>
+
+</body>
+</html>

+ 126 - 0
node_modules/cos-js-sdk-v5/demo/sts-post.html

@@ -0,0 +1,126 @@
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Ajax Post 上传</title>
+    <style>
+        h1, h2 {
+            font-weight: normal;
+        }
+
+        #msg {
+            margin-top: 10px;
+        }
+    </style>
+</head>
+<body>
+
+<h1>Ajax Post 上传</h1>
+
+<input id="fileSelector" type="file">
+<input id="submitBtn" type="submit">
+
+<div id="msg"></div>
+
+<script src="common/cos-auth.min.js"></script>
+<script>
+    (function () {
+        // 请求用到的参数
+        var Bucket = 'test-1250000000';
+        var Region = 'ap-guangzhou';
+        var protocol = location.protocol === 'https:' ? 'https:' : 'http:';
+        var prefix = protocol + '//' + Bucket + '.cos.' + Region + '.myqcloud.com/';
+
+        // 对更多字符编码的 url encode 格式
+        var camSafeUrlEncode = function (str) {
+            return encodeURIComponent(str)
+                .replace(/!/g, '%21')
+                .replace(/'/g, '%27')
+                .replace(/\(/g, '%28')
+                .replace(/\)/g, '%29')
+                .replace(/\*/g, '%2A');
+        };
+
+        // 计算签名
+        var getAuthorization = function (options, callback) {
+            // var url = 'http://127.0.0.1:3000/sts';
+            var url = '../server/sts.php';
+            var xhr = new XMLHttpRequest();
+            xhr.open('GET', url, true);
+            xhr.onreadystatechange = function (e) {
+                if (xhr.readyState === 4) {
+                    if (xhr.status === 200) {
+                        var credentials;
+                        try {
+                            credentials = (new Function('return ' + xhr.responseText))().credentials;
+                        } catch (e) {}
+                        if (credentials) {
+                            callback(null, {
+                                SecurityToken: credentials.sessionToken,
+                                Authorization: CosAuth({
+                                    SecretId: credentials.tmpSecretId,
+                                    SecretKey: credentials.tmpSecretKey,
+                                    Method: options.Method,
+                                    Pathname: options.Pathname,
+                                })
+                            });
+                        } else {
+                            console.error(xhr.responseText);
+                            callback('获取签名出错');
+                        }
+                    } else {
+                        callback('获取签名出错');
+                    }
+                }
+            };
+            xhr.send();
+        };
+
+        // 上传文件
+        var uploadFile = function (file, callback) {
+            var Key = 'dir/' + file.name; // 这里指定上传目录和文件名
+            getAuthorization({Method: 'POST', Pathname: '/'}, function (err, info) {
+                var fd = new FormData();
+                fd.append('key', Key);
+                fd.append('signature', info.Authorization);
+                fd.append('Content-Type', '');
+                info.SecurityToken && fd.append('x-cos-security-token', info.SecurityToken);
+                fd.append('file', file); // file 字段放在表单最后,避免文件内容过长影响签名判断和鉴权
+                var url = prefix;
+                var xhr = new XMLHttpRequest();
+                xhr.open('POST', url, true);
+                xhr.upload.onprogress = function (e) {
+                    console.log('上传进度 ' + (Math.round(e.loaded / e.total * 10000) / 100) + '%');
+                };
+                xhr.onload = function () {
+                    if (Math.floor(xhr.status / 100) === 2) {
+                        var ETag = xhr.getResponseHeader('etag');
+                        callback(null, {url: prefix + camSafeUrlEncode(Key).replace(/%2F/g, '/'), ETag: ETag});
+                    } else {
+                        callback('文件 ' + Key + ' 上传失败,状态码:' + xhr.status);
+                    }
+                };
+                xhr.onerror = function () {
+                    callback('文件 ' + Key + ' 上传失败,请检查是否没配置 CORS 跨域规则');
+                };
+                xhr.send(fd);
+            });
+        };
+
+        // 监听表单提交
+        document.getElementById('submitBtn').onclick = function (e) {
+            var file = document.getElementById('fileSelector').files[0];
+            if (!file) {
+                document.getElementById('msg').innerText = '未选择上传文件';
+                return;
+            }
+            file && uploadFile(file, function (err, data) {
+                console.log(err || data);
+                document.getElementById('msg').innerText = err ? err : ('上传成功,ETag=' + data.ETag);
+            });
+        };
+    })();
+</script>
+
+</body>
+</html>

+ 129 - 0
node_modules/cos-js-sdk-v5/demo/sts-put-server-key.html

@@ -0,0 +1,129 @@
+
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Ajax Put 上传</title>
+    <style>
+        h1, h2 {
+            font-weight: normal;
+        }
+
+        #msg {
+            margin-top: 10px;
+        }
+    </style>
+</head>
+<body>
+
+<h1>Ajax Put 上传</h1>
+
+<input id="fileSelector" type="file">
+<input id="submitBtn" type="submit">
+
+<div id="msg"></div>
+
+<script src="common/cos-auth.min.js"></script>
+<script>
+    (function () {
+        // 请求用到的参数
+        var Bucket = 'test-1250000000';
+        var Region = 'ap-guangzhou';
+        var protocol = location.protocol === 'https:' ? 'https:' : 'http:';
+        var prefix = protocol + '//' + Bucket + '.cos.' + Region + '.myqcloud.com/';
+
+        // 对更多字符编码的 url encode 格式
+        var camSafeUrlEncode = function (str) {
+            return encodeURIComponent(str)
+                .replace(/!/g, '%21')
+                .replace(/'/g, '%27')
+                .replace(/\(/g, '%28')
+                .replace(/\)/g, '%29')
+                .replace(/\*/g, '%2A');
+        };
+
+        // 计算签名
+        var getKeyAndAuth = function (options, callback) {
+            var url = 'http://127.0.0.1:3000/sts-server-key';
+            var xhr = new XMLHttpRequest();
+            xhr.open('GET', url, true);
+            xhr.onload = function (e) {
+                var result, credentials;
+                try {
+                    result = (new Function('return ' + xhr.responseText))();
+                    credentials = result.credentials;
+                } catch (e) {}
+                if (result && credentials) {
+                    callback(null, {
+                        Key: result.Key, // 这里在后端加一个字段决定上传的文件名
+                        SecurityToken: credentials.sessionToken,
+                        Authorization: CosAuth({
+                            SecretId: credentials.tmpSecretId,
+                            SecretKey: credentials.tmpSecretKey,
+                            Method: options.Method,
+                            Pathname: '/' + options.Key,
+                        }),
+                    });
+                } else {
+                    console.error(xhr.responseText);
+                    callback('获取签名出错');
+                }
+            };
+            xhr.onerror = function (e) {
+                callback('获取签名出错');
+            };
+            xhr.send();
+        };
+
+        // 上传文件
+        var uploadFile = function (file, callback) {
+            getKeyAndAuth({Method: 'PUT', FileName: file.name}, function (err, info) {
+                var Key = info.Key;
+
+                if (err) {
+                    alert(err);
+                    return;
+                }
+
+                var auth = info.Authorization;
+                var SecurityToken = info.SecurityToken;
+                var url = prefix + camSafeUrlEncode(Key).replace(/%2F/g, '/');
+                var xhr = new XMLHttpRequest();
+                xhr.open('PUT', url, true);
+                xhr.setRequestHeader('Authorization', auth);
+                SecurityToken && xhr.setRequestHeader('x-cos-security-token', SecurityToken);
+                xhr.upload.onprogress = function (e) {
+                    console.log('上传进度 ' + (Math.round(e.loaded / e.total * 10000) / 100) + '%');
+                };
+                xhr.onload = function () {
+                    if (xhr.status === 200 || xhr.status === 206) {
+                        var ETag = xhr.getResponseHeader('etag');
+                        callback(null, {url: url, ETag: ETag});
+                    } else {
+                        callback('文件 ' + Key + ' 上传失败,状态码:' + xhr.status);
+                    }
+                };
+                xhr.onerror = function () {
+                    callback('文件 ' + Key + ' 上传失败,请检查是否没配置 CORS 跨域规则');
+                };
+                xhr.send(file);
+            });
+        };
+
+        // 监听表单提交
+        document.getElementById('submitBtn').onclick = function (e) {
+            var file = document.getElementById('fileSelector').files[0];
+            if (!file) {
+                document.getElementById('msg').innerText = '未选择上传文件';
+                return;
+            }
+            file && uploadFile(file, function (err, data) {
+                console.log(err || data);
+                document.getElementById('msg').innerText = err ? err : ('上传成功,ETag=' + data.ETag);
+            });
+        };
+    })();
+</script>
+
+</body>
+</html>

+ 128 - 0
node_modules/cos-js-sdk-v5/demo/sts-put.html

@@ -0,0 +1,128 @@
+
+<!doctype html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <title>Ajax Put 上传</title>
+    <style>
+        h1, h2 {
+            font-weight: normal;
+        }
+
+        #msg {
+            margin-top: 10px;
+        }
+    </style>
+</head>
+<body>
+
+<h1>Ajax Put 上传</h1>
+
+<input id="fileSelector" type="file">
+<input id="submitBtn" type="submit">
+
+<div id="msg"></div>
+
+<script src="common/cos-auth.min.js"></script>
+<script>
+    (function () {
+        // 请求用到的参数
+        var Bucket = 'test-1250000000';
+        var Region = 'ap-guangzhou';
+        var protocol = location.protocol === 'https:' ? 'https:' : 'http:';
+        var prefix = protocol + '//' + Bucket + '.cos.' + Region + '.myqcloud.com/';
+
+        // 对更多字符编码的 url encode 格式
+        var camSafeUrlEncode = function (str) {
+            return encodeURIComponent(str)
+                .replace(/!/g, '%21')
+                .replace(/'/g, '%27')
+                .replace(/\(/g, '%28')
+                .replace(/\)/g, '%29')
+                .replace(/\*/g, '%2A');
+        };
+
+        // 计算签名
+        var getAuthorization = function (options, callback) {
+            // var url = 'http://127.0.0.1:3000/sts-auth';
+            var url = '../server/sts.php';
+            var xhr = new XMLHttpRequest();
+            xhr.open('GET', url, true);
+            xhr.onload = function (e) {
+                var credentials;
+                try {
+                    credentials = (new Function('return ' + xhr.responseText))().credentials;
+                } catch (e) {}
+                if (credentials) {
+                    callback(null, {
+                        SecurityToken: credentials.sessionToken,
+                        Authorization: CosAuth({
+                            SecretId: credentials.tmpSecretId,
+                            SecretKey: credentials.tmpSecretKey,
+                            Method: options.Method,
+                            Pathname: options.Pathname,
+                        })
+                    });
+                } else {
+                    console.error(xhr.responseText);
+                    callback('获取签名出错');
+                }
+            };
+            xhr.onerror = function (e) {
+                callback('获取签名出错');
+            };
+            xhr.send();
+        };
+
+        // 上传文件
+        var uploadFile = function (file, callback) {
+            var Key = 'dir/' + file.name; // 这里指定上传目录和文件名
+            getAuthorization({Method: 'PUT', Pathname: '/' + Key}, function (err, info) {
+
+                if (err) {
+                    alert(err);
+                    return;
+                }
+
+                var auth = info.Authorization;
+                var SecurityToken = info.SecurityToken;
+                var url = prefix + camSafeUrlEncode(Key).replace(/%2F/g, '/');
+                var xhr = new XMLHttpRequest();
+                xhr.open('PUT', url, true);
+                xhr.setRequestHeader('Authorization', auth);
+                SecurityToken && xhr.setRequestHeader('x-cos-security-token', SecurityToken);
+                xhr.upload.onprogress = function (e) {
+                    console.log('上传进度 ' + (Math.round(e.loaded / e.total * 10000) / 100) + '%');
+                };
+                xhr.onload = function () {
+                    if (xhr.status === 200 || xhr.status === 206) {
+                        var ETag = xhr.getResponseHeader('etag');
+                        callback(null, {url: url, ETag: ETag});
+                    } else {
+                        callback('文件 ' + Key + ' 上传失败,状态码:' + xhr.status);
+                    }
+                };
+                xhr.onerror = function () {
+                    callback('文件 ' + Key + ' 上传失败,请检查是否没配置 CORS 跨域规则');
+                };
+                xhr.send(file);
+            });
+        };
+
+        // 监听表单提交
+        document.getElementById('submitBtn').onclick = function (e) {
+            var file = document.getElementById('fileSelector').files[0];
+            if (!file) {
+                document.getElementById('msg').innerText = '未选择上传文件';
+                return;
+            }
+            file && uploadFile(file, function (err, data) {
+                console.log(err || data);
+                document.getElementById('msg').innerText = err ? err : ('上传成功,ETag=' + data.ETag);
+            });
+        };
+    })();
+</script>
+
+</body>
+</html>

+ 56 - 0
node_modules/cos-js-sdk-v5/demo/vueDemo/index.html

@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <meta http-equiv="X-UA-Compatible" content="IE=edge">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <title>COS-SDK-Vue-demo</title>
+  <script src="./vue.min.js"></script>
+  <!-- 使用时替换为当前最新版sdk -->
+  <script src="../../dist/cos-js-sdk-v5.js"></script>
+  <script src="index.js"></script>
+  <style>
+    table {width: 100%; border: solid 1px #ddd;}
+    table td {padding: 0 10px;}
+    .more-btn {display: block; margin: 10px auto 0;}
+  </style>
+</head>
+<body>
+  <div id="app">
+    <div class="nav">
+      <span v-for="(item, index) in navList" :key="index" style="margin-right: 5px;">
+        <a href="javascript:void(0)" @click="navClick(item)">{{item.name}}</a>
+        <span v-if="index !== navList.length - 1">/</span>
+      </span>
+    </div>
+    <div style="margin: 10px 0;">
+      <button @click="uploadFileClick" style="margin: 0 10px 0 0;">上传文件</button>
+      <button @click="uploadFolderClick">上传文件夹</button>
+      <input type="file" style="display: none;" @change="uploadChange" class="file-select">
+      <input type="file" style="display: none;" @change="uploadChange" class="folder-select" webkitdirectory multiple>
+    </div>
+    <div class="file-list">
+      <table border="1" cellpadding="0" cellspacing="0">
+        <thead>
+          <th v-for="(item, index) in columns" :key="index">{{item.label}}</th>
+        </thead>
+        <tbody>
+          <tr v-for="(item, index) in list" :key="index">
+            <td>
+              <a v-if="item.isDir" href="javascript:void(0)" @click="openFolder(item.Prefix)">{{item.name}}</a>
+              <span v-else>{{item.name}}</span>
+            </td>
+            <td>{{item.Size || '-'}}</td>
+            <td>{{item.LastModified || '-'}}</td>
+            <td>
+              <a v-if="!item.isDir" href="javascript:void(0)" @click="downloadFile(item)">下载</a>
+              <a v-if="!item.isDir" href="javascript:void(0)" @click="deleteFile(item)">删除</a>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+      <button v-if="hasMore === 'true'" class="more-btn" @click="loadMore">加载更多</button>
+    </div>
+  </div>
+</body>
+</html>

+ 185 - 0
node_modules/cos-js-sdk-v5/demo/vueDemo/index.js

@@ -0,0 +1,185 @@
+window.onload = function() {
+  const Bucket = 'examplebucket-1250000000';  /* 存储桶 */
+  const Region = 'ap-beijing';  /* 存储桶所在地域,必须字段 */
+  // SecretId 和 SecretKey请登录 https://console.cloud.tencent.com/cam/capi 进行查看和管理
+  const cos = new COS({
+    SecretId: '',
+    SecretKey: '',
+  });
+
+  /*
+    实现了以下功能
+    - 文件列表
+    - 上传文件
+    - 上传文件夹
+    - 下载文件
+    - 删除文件
+  */
+  const vm = new Vue({
+    el: '#app',
+    data() {
+      return {
+        columns: [
+          { label: '名称', value: 'Key' },
+          { label: '大小', value: 'Size' },
+          { label: '修改时间', value: 'LastModified' },
+          { label: '操作', value: 'action' }
+        ],
+        list: [],
+        Prefix: '',
+        Marker: '',
+        hasMore: false,
+      }
+    },
+    computed: {
+      // 面包屑导航条
+      navList() {
+        const prefixes = this.Prefix.split('/').filter(Boolean);
+        const folders = prefixes.map((item, index) => {
+          return {
+            name: item,
+            Prefix: prefixes.slice(0, index + 1).join('/') + '/',
+          };
+        });
+        return [{ name: Bucket, Prefix: ''}].concat(folders);
+      },
+    },
+    created() {
+      this.getFileList();
+    },
+    methods: {
+      // 查询文件列表
+      getFileList(loadMore) {
+        const { Prefix, Marker } = this;
+        cos.getBucket({
+          Bucket, /* 必须 */
+          Region,     /* 存储桶所在地域,必须字段 */
+          Prefix,              /* 非必须 */
+          Marker,       /* 非必须 */
+          Delimiter: '/',            /* 非必须 */
+       }, (err, data) => {
+          if(err) {
+            console.log(err);
+            return;
+          }
+          const folder = data.CommonPrefixes.map((item) => {
+            return {
+              Prefix: item.Prefix,
+              name: item.Prefix.replace(Prefix, '').slice(0,-1),
+              isDir: true,
+            }
+          });
+          const files = data.Contents.filter((item) => !item.Key.endsWith('/'))
+                        .map((item) => {
+                          return {
+                            ...item,
+                            name: item.Key.replace(Prefix, ''),
+                          }
+                        });
+          const list = folder.concat(files);
+          this.hasMore = data.IsTruncated;
+          this.Marker = data.NextMarker || '';
+          if (loadMore) {
+            this.list = [...this.list, ...list];
+          } else {
+            this.list = list;
+          }
+       });
+      },
+      // 点击面包屑
+      navClick(item) {
+        this.openFolder(item.Prefix);
+      },
+      // 打开文件夹
+      openFolder(prefix) {
+        this.Prefix = prefix;
+        this.hasMore = false;
+        this.Marker = '';
+        this.getFileList();
+      },
+      // 上传文件
+      uploadFileClick() {
+        document.querySelectorAll('.file-select')[0].click();
+      },
+      // 上传文件夹
+      uploadFolderClick() {
+        document.querySelectorAll('.folder-select')[0].click();
+      },
+      // 上传
+      uploadChange(events) {
+        const files = events.currentTarget.files;
+        const uploadFileList = [...files].map((file) => {
+          const path = file.webkitRelativePath || file.name;
+          return {
+            Bucket,
+            Region,
+            Key: this.Prefix + path,
+            Body: file,
+          }
+        });
+        cos.uploadFiles({
+          files: uploadFileList,
+          SliceSize: 1024 * 1024 * 10,    /* 设置大于10MB采用分块上传 */
+          onProgress: function (info) {
+              var percent = parseInt(info.percent * 10000) / 100;
+              var speed = parseInt(info.speed / 1024 / 1024 * 100) / 100;
+              console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;');
+          },
+          onFileFinish: function (err, data, options) {
+              console.log(options.Key + '上传' + (err ? '失败' : '完成'));
+          },
+       }, (err, data) => {
+          if (err) {
+            console.log('上传失败', err);
+            return;
+          }
+          // 刷新列表前初始化
+          this.hasMore = false;
+          this.Marker = '';
+          this.getFileList();
+       });
+      },
+      // 加载更多
+      loadMore() {
+        this.getFileList(true);
+      },
+      // 下载
+      downloadFile(file) {
+        cos.getObjectUrl({
+          Bucket, /* 必须 */
+          Region,     /* 存储桶所在地域,必须字段 */
+          Key: file.Key,              /* 必须 */
+        }, function(err, data) {
+          if (err) {
+            console.log(err);
+            return;
+          }
+          const url = data.Url + (data.Url.indexOf('?') > -1 ? '&' : '?') + 'response-content-disposition=attachment'; // 补充强制下载的参数
+          // 使用iframe下载
+          const elemIF = document.createElement("iframe");
+          elemIF.src = url;
+          elemIF.style.display = "none";
+          document.body.appendChild(elemIF);
+        });
+      },
+      // 删除
+      deleteFile(file) {
+        cos.deleteObject({
+          Bucket, /* 必须 */
+          Region,     /* 存储桶所在地域,必须字段 */
+          Key: file.Key        /* 必须 */
+       }, (err, data) => {
+          if (err) {
+            console.log(err);
+            return;
+          }
+          // 刷新列表前初始化
+          this.hasMore = false;
+          this.Marker = '';
+          this.getFileList();
+       });
+      },
+    },
+  });
+}
+

File diff suppressed because it is too large
+ 6 - 0
node_modules/cos-js-sdk-v5/demo/vueDemo/vue.min.js


File diff suppressed because it is too large
+ 15644 - 0
node_modules/cos-js-sdk-v5/dist/cos-js-sdk-v5.js


File diff suppressed because it is too large
+ 1 - 0
node_modules/cos-js-sdk-v5/dist/cos-js-sdk-v5.min.js


File diff suppressed because it is too large
+ 2581 - 0
node_modules/cos-js-sdk-v5/index.d.ts


+ 2 - 0
node_modules/cos-js-sdk-v5/index.js

@@ -0,0 +1,2 @@
+var COS = require('./src/cos');
+module.exports = COS;

+ 12 - 0
node_modules/cos-js-sdk-v5/jest.config.js

@@ -0,0 +1,12 @@
+module.exports = {
+  collectCoverage: true,  // 是否显示覆盖率报告
+  // 告诉 jest 哪些文件需要经过单元测试测试
+  collectCoverageFrom: ['**/src/*.js'],
+  coverageThreshold: {
+    global: {
+      statements: 90, // 保证每个语句都执行了
+      functions: 90, // 保证每个函数都调用了
+      branches: 90, // 保证每个 if 等分支代码都执行了
+    },
+  },
+};

+ 170 - 0
node_modules/cos-js-sdk-v5/lib/base64.js

@@ -0,0 +1,170 @@
+/*
+ * $Id: base64.js,v 2.15 2014/04/05 12:58:57 dankogai Exp dankogai $
+ *
+ *  Licensed under the BSD 3-Clause License.
+ *    http://opensource.org/licenses/BSD-3-Clause
+ *
+ *  References:
+ *    http://en.wikipedia.org/wiki/Base64
+ */
+
+var Base64 = (function(global) {
+  global = global || {};
+  'use strict';
+  // existing version for noConflict()
+  var _Base64 = global.Base64;
+  var version = "2.1.9";
+  // if node.js, we use Buffer
+  var buffer;
+  // constants
+  var b64chars
+      = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+  var b64tab = function(bin) {
+      var t = {};
+      for (var i = 0, l = bin.length; i < l; i++) t[bin.charAt(i)] = i;
+      return t;
+  }(b64chars);
+  var fromCharCode = String.fromCharCode;
+  // encoder stuff
+  var cb_utob = function(c) {
+      if (c.length < 2) {
+          var cc = c.charCodeAt(0);
+          return cc < 0x80 ? c
+              : cc < 0x800 ? (fromCharCode(0xc0 | (cc >>> 6))
+                              + fromCharCode(0x80 | (cc & 0x3f)))
+              : (fromCharCode(0xe0 | ((cc >>> 12) & 0x0f))
+                 + fromCharCode(0x80 | ((cc >>>  6) & 0x3f))
+                 + fromCharCode(0x80 | ( cc         & 0x3f)));
+      } else {
+          var cc = 0x10000
+              + (c.charCodeAt(0) - 0xD800) * 0x400
+              + (c.charCodeAt(1) - 0xDC00);
+          return (fromCharCode(0xf0 | ((cc >>> 18) & 0x07))
+                  + fromCharCode(0x80 | ((cc >>> 12) & 0x3f))
+                  + fromCharCode(0x80 | ((cc >>>  6) & 0x3f))
+                  + fromCharCode(0x80 | ( cc         & 0x3f)));
+      }
+  };
+  var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;
+  var utob = function(u) {
+      return u.replace(re_utob, cb_utob);
+  };
+  var cb_encode = function(ccc) {
+      var padlen = [0, 2, 1][ccc.length % 3],
+      ord = ccc.charCodeAt(0) << 16
+          | ((ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8)
+          | ((ccc.length > 2 ? ccc.charCodeAt(2) : 0)),
+      chars = [
+          b64chars.charAt( ord >>> 18),
+          b64chars.charAt((ord >>> 12) & 63),
+          padlen >= 2 ? '=' : b64chars.charAt((ord >>> 6) & 63),
+          padlen >= 1 ? '=' : b64chars.charAt(ord & 63)
+      ];
+      return chars.join('');
+  };
+  var btoa = global.btoa ? function(b) {
+      return global.btoa(b);
+  } : function(b) {
+      return b.replace(/[\s\S]{1,3}/g, cb_encode);
+  };
+  var _encode = buffer ? function (u) {
+      return (u.constructor === buffer.constructor ? u : new buffer(u))
+      .toString('base64')
+  }
+  : function (u) { return btoa(utob(u)) }
+  ;
+  var encode = function(u, urisafe) {
+      return !urisafe
+          ? _encode(String(u))
+          : _encode(String(u)).replace(/[+\/]/g, function(m0) {
+              return m0 == '+' ? '-' : '_';
+          }).replace(/=/g, '');
+  };
+  var encodeURI = function(u) { return encode(u, true) };
+  // decoder stuff
+  var re_btou = new RegExp([
+      '[\xC0-\xDF][\x80-\xBF]',
+      '[\xE0-\xEF][\x80-\xBF]{2}',
+      '[\xF0-\xF7][\x80-\xBF]{3}'
+  ].join('|'), 'g');
+  var cb_btou = function(cccc) {
+      switch(cccc.length) {
+      case 4:
+          var cp = ((0x07 & cccc.charCodeAt(0)) << 18)
+              |    ((0x3f & cccc.charCodeAt(1)) << 12)
+              |    ((0x3f & cccc.charCodeAt(2)) <<  6)
+              |     (0x3f & cccc.charCodeAt(3)),
+          offset = cp - 0x10000;
+          return (fromCharCode((offset  >>> 10) + 0xD800)
+                  + fromCharCode((offset & 0x3FF) + 0xDC00));
+      case 3:
+          return fromCharCode(
+              ((0x0f & cccc.charCodeAt(0)) << 12)
+                  | ((0x3f & cccc.charCodeAt(1)) << 6)
+                  |  (0x3f & cccc.charCodeAt(2))
+          );
+      default:
+          return  fromCharCode(
+              ((0x1f & cccc.charCodeAt(0)) << 6)
+                  |  (0x3f & cccc.charCodeAt(1))
+          );
+      }
+  };
+  var btou = function(b) {
+      return b.replace(re_btou, cb_btou);
+  };
+  var cb_decode = function(cccc) {
+      var len = cccc.length,
+      padlen = len % 4,
+      n = (len > 0 ? b64tab[cccc.charAt(0)] << 18 : 0)
+          | (len > 1 ? b64tab[cccc.charAt(1)] << 12 : 0)
+          | (len > 2 ? b64tab[cccc.charAt(2)] <<  6 : 0)
+          | (len > 3 ? b64tab[cccc.charAt(3)]       : 0),
+      chars = [
+          fromCharCode( n >>> 16),
+          fromCharCode((n >>>  8) & 0xff),
+          fromCharCode( n         & 0xff)
+      ];
+      chars.length -= [0, 0, 2, 1][padlen];
+      return chars.join('');
+  };
+  var atob = global.atob ? function(a) {
+      return global.atob(a);
+  } : function(a){
+      return a.replace(/[\s\S]{1,4}/g, cb_decode);
+  };
+  var _decode = buffer ? function(a) {
+      return (a.constructor === buffer.constructor
+              ? a : new buffer(a, 'base64')).toString();
+  }
+  : function(a) { return btou(atob(a)) };
+  var decode = function(a){
+      return _decode(
+          String(a).replace(/[-_]/g, function(m0) { return m0 == '-' ? '+' : '/' })
+              .replace(/[^A-Za-z0-9\+\/]/g, '')
+      );
+  };
+  var noConflict = function() {
+      var Base64 = global.Base64;
+      global.Base64 = _Base64;
+      return Base64;
+  };
+  // export Base64
+  var Base64 = {
+      VERSION: version,
+      atob: atob,
+      btoa: btoa,
+      fromBase64: decode,
+      toBase64: encode,
+      utob: utob,
+      encode: encode,
+      encodeURI: encodeURI,
+      btou: btou,
+      decode: decode,
+      noConflict: noConflict
+  };
+  return Base64;
+})();
+
+module.exports = Base64;
+

File diff suppressed because it is too large
+ 1 - 0
node_modules/cos-js-sdk-v5/lib/beacon.min.js


File diff suppressed because it is too large
+ 128 - 0
node_modules/cos-js-sdk-v5/lib/crypto.js


+ 167 - 0
node_modules/cos-js-sdk-v5/lib/json2xml.js

@@ -0,0 +1,167 @@
+//copyright Ryan Day 2010 <http://ryanday.org>, Joscha Feth 2013 <http://www.feth.com> [MIT Licensed]
+
+var element_start_char =
+    "a-zA-Z_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FFF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD";
+var element_non_start_char = "\-.0-9\u00B7\u0300-\u036F\u203F\u2040";
+var element_replace = new RegExp("^([^" + element_start_char + "])|^((x|X)(m|M)(l|L))|([^" + element_start_char + element_non_start_char + "])", "g");
+var not_safe_in_xml = /[^\x09\x0A\x0D\x20-\xFF\x85\xA0-\uD7FF\uE000-\uFDCF\uFDE0-\uFFFD]/gm;
+
+var objKeys = function (obj) {
+    var l = [];
+    if (obj instanceof Object) {
+        for (var k in obj) {
+            if (obj.hasOwnProperty(k)) {
+                l.push(k);
+            }
+        }
+    }
+    return l;
+};
+var process_to_xml = function (node_data, options) {
+
+    var makeNode = function (name, content, attributes, level, hasSubNodes) {
+        var indent_value = options.indent !== undefined ? options.indent : "\t";
+        var indent = options.prettyPrint ? '\n' + new Array(level).join(indent_value) : '';
+        if (options.removeIllegalNameCharacters) {
+            name = name.replace(element_replace, '_');
+        }
+
+        var node = [indent, '<', name, (attributes || '')];
+        if (content && content.length > 0) {
+            node.push('>')
+            node.push(content);
+            hasSubNodes && node.push(indent);
+            node.push('</');
+            node.push(name);
+            node.push('>');
+        } else {
+            node.push('/>');
+        }
+        return node.join('');
+    };
+
+    return (function fn(node_data, node_descriptor, level) {
+        var type = typeof node_data;
+        if ((Array.isArray) ? Array.isArray(node_data) : node_data instanceof Array) {
+            type = 'array';
+        } else if (node_data instanceof Date) {
+            type = 'date';
+        }
+
+        switch (type) {
+            //if value is an array create child nodes from values
+            case 'array':
+                var ret = [];
+                node_data.map(function (v) {
+                    ret.push(fn(v, 1, level + 1));
+                    //entries that are values of an array are the only ones that can be special node descriptors
+                });
+                options.prettyPrint && ret.push('\n');
+                return ret.join('');
+                break;
+
+            case 'date':
+                // cast dates to ISO 8601 date (soap likes it)
+                return node_data.toJSON ? node_data.toJSON() : node_data + '';
+                break;
+
+            case 'object':
+                var nodes = [];
+                for (var name in node_data) {
+                    if (node_data.hasOwnProperty(name)) {
+                        if (node_data[name] instanceof Array) {
+                            for (var j = 0; j < node_data[name].length; j++) {
+                                if (node_data[name].hasOwnProperty(j)) {
+                                    nodes.push(makeNode(name, fn(node_data[name][j], 0, level + 1), null, level + 1, objKeys(node_data[name][j]).length));
+                                }
+                            }
+                        } else {
+                            nodes.push(makeNode(name, fn(node_data[name], 0, level + 1), null, level + 1));
+                        }
+                    }
+                }
+                options.prettyPrint && nodes.length > 0 && nodes.push('\n');
+                return nodes.join('');
+                break;
+
+            case 'function':
+                return node_data();
+                break;
+
+            default:
+                return options.escape ? esc(node_data) : '' + node_data;
+        }
+
+    }(node_data, 0, 0))
+};
+
+
+var xml_header = function (standalone) {
+    var ret = ['<?xml version="1.0" encoding="UTF-8"'];
+
+    if (standalone) {
+        ret.push(' standalone="yes"');
+    }
+    ret.push('?>');
+
+    return ret.join('');
+};
+
+function esc(str) {
+    return ('' + str).replace(/&/g, '&amp;')
+        .replace(/</g, '&lt;')
+        .replace(/>/g, '&gt;')
+        .replace(/'/g, '&apos;')
+        .replace(/"/g, '&quot;')
+        .replace(not_safe_in_xml, '');
+}
+
+module.exports = function (obj, options) {
+    if (!options) {
+        options = {
+            xmlHeader: {
+                standalone: true
+            },
+            prettyPrint: true,
+            indent: "  ",
+            escape: true,
+        };
+    }
+
+    if (typeof obj == 'string') {
+        try {
+            obj = JSON.parse(obj.toString());
+        } catch (e) {
+            return false;
+        }
+    }
+
+    var xmlheader = '';
+    var docType = '';
+    if (options) {
+        if (typeof options == 'object') {
+            // our config is an object
+
+            if (options.xmlHeader) {
+                // the user wants an xml header
+                xmlheader = xml_header(!!options.xmlHeader.standalone);
+            }
+
+            if (typeof options.docType != 'undefined') {
+                docType = '<!DOCTYPE ' + options.docType + '>'
+            }
+        } else {
+            // our config is a boolean value, so just add xml header
+            xmlheader = xml_header();
+        }
+    }
+    options = options || {}
+
+    var ret = [
+        xmlheader,
+        (options.prettyPrint && docType ? '\n' : ''),
+        docType,
+        process_to_xml(obj, options)
+    ];
+    return ret.join('').replace(/\n{2,}/g, '\n').replace(/\s+$/g, '');
+};

+ 618 - 0
node_modules/cos-js-sdk-v5/lib/md5.js

@@ -0,0 +1,618 @@
+/* https://github.com/emn178/js-md5 */
+(function () {
+    'use strict';
+
+    var WINDOW = typeof window === 'object';
+    var root = WINDOW ? window : {};
+    if (root.JS_MD5_NO_WINDOW) {
+        WINDOW = false;
+    }
+    var WEB_WORKER = !WINDOW && typeof self === 'object';
+    if (WEB_WORKER) {
+        root = self;
+    }
+    var COMMON_JS = !root.JS_MD5_NO_COMMON_JS && typeof module === 'object' && module.exports;
+    var AMD = typeof define === 'function' && define.amd;
+    var ARRAY_BUFFER = !root.JS_MD5_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined';
+    var HEX_CHARS = '0123456789abcdef'.split('');
+    var EXTRA = [128, 32768, 8388608, -2147483648];
+    var SHIFT = [0, 8, 16, 24];
+    var OUTPUT_TYPES = ['hex', 'array', 'digest', 'buffer', 'arrayBuffer', 'base64'];
+    var BASE64_ENCODE_CHAR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split('');
+
+    var blocks = [], buffer8;
+    if (ARRAY_BUFFER) {
+        var buffer = new ArrayBuffer(68);
+        buffer8 = new Uint8Array(buffer);
+        blocks = new Uint32Array(buffer);
+    }
+
+    if (root.JS_MD5_NO_NODE_JS || !Array.isArray) {
+        Array.isArray = function (obj) {
+            return Object.prototype.toString.call(obj) === '[object Array]';
+        };
+    }
+
+    if (ARRAY_BUFFER && (root.JS_MD5_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) {
+        ArrayBuffer.isView = function (obj) {
+            return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer;
+        };
+    }
+
+    /**
+     * @method hex
+     * @memberof md5
+     * @description Output hash as hex string
+     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+     * @returns {String} Hex string
+     * @example
+     * md5.hex('The quick brown fox jumps over the lazy dog');
+     * // equal to
+     * md5('The quick brown fox jumps over the lazy dog');
+     */
+    /**
+     * @method digest
+     * @memberof md5
+     * @description Output hash as bytes array
+     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+     * @returns {Array} Bytes array
+     * @example
+     * md5.digest('The quick brown fox jumps over the lazy dog');
+     */
+    /**
+     * @method array
+     * @memberof md5
+     * @description Output hash as bytes array
+     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+     * @returns {Array} Bytes array
+     * @example
+     * md5.array('The quick brown fox jumps over the lazy dog');
+     */
+    /**
+     * @method arrayBuffer
+     * @memberof md5
+     * @description Output hash as ArrayBuffer
+     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+     * @returns {ArrayBuffer} ArrayBuffer
+     * @example
+     * md5.arrayBuffer('The quick brown fox jumps over the lazy dog');
+     */
+    /**
+     * @method buffer
+     * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead.
+     * @memberof md5
+     * @description Output hash as ArrayBuffer
+     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+     * @returns {ArrayBuffer} ArrayBuffer
+     * @example
+     * md5.buffer('The quick brown fox jumps over the lazy dog');
+     */
+    /**
+     * @method base64
+     * @memberof md5
+     * @description Output hash as base64 string
+     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+     * @returns {String} base64 string
+     * @example
+     * md5.base64('The quick brown fox jumps over the lazy dog');
+     */
+    var createOutputMethod = function (outputType) {
+        return function (message, isBinStr) {
+            return new Md5(true).update(message, isBinStr)[outputType]();
+        };
+    };
+
+    /**
+     * @method create
+     * @memberof md5
+     * @description Create Md5 object
+     * @returns {Md5} Md5 object.
+     * @example
+     * var hash = md5.create();
+     */
+    /**
+     * @method update
+     * @memberof md5
+     * @description Create and update Md5 object
+     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+     * @returns {Md5} Md5 object.
+     * @example
+     * var hash = md5.update('The quick brown fox jumps over the lazy dog');
+     * // equal to
+     * var hash = md5.create();
+     * hash.update('The quick brown fox jumps over the lazy dog');
+     */
+    var createMethod = function () {
+        var method = createOutputMethod('hex');
+        method.getCtx = method.create = function () {
+            return new Md5();
+        };
+        method.update = function (message) {
+            return method.create().update(message);
+        };
+        for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
+            var type = OUTPUT_TYPES[i];
+            method[type] = createOutputMethod(type);
+        }
+        return method;
+    };
+
+    /**
+     * Md5 class
+     * @class Md5
+     * @description This is internal class.
+     * @see {@link md5.create}
+     */
+    function Md5(sharedMemory) {
+        if (sharedMemory) {
+            blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] =
+                blocks[4] = blocks[5] = blocks[6] = blocks[7] =
+                    blocks[8] = blocks[9] = blocks[10] = blocks[11] =
+                        blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
+            this.blocks = blocks;
+            this.buffer8 = buffer8;
+        } else {
+            if (ARRAY_BUFFER) {
+                var buffer = new ArrayBuffer(68);
+                this.buffer8 = new Uint8Array(buffer);
+                this.blocks = new Uint32Array(buffer);
+            } else {
+                this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
+            }
+        }
+        this.h0 = this.h1 = this.h2 = this.h3 = this.start = this.bytes = this.hBytes = 0;
+        this.finalized = this.hashed = false;
+        this.first = true;
+    }
+
+    /**
+     * @method update
+     * @memberof Md5
+     * @instance
+     * @description Update hash
+     * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+     * @returns {Md5} Md5 object.
+     * @see {@link md5.update}
+     */
+    Md5.prototype.update = function (message, isBinStr) {
+        if (this.finalized) {
+            return;
+        }
+
+        var code, index = 0, i, length = message.length, blocks = this.blocks;
+        var buffer8 = this.buffer8;
+
+        while (index < length) {
+            if (this.hashed) {
+                this.hashed = false;
+                blocks[0] = blocks[16];
+                blocks[16] = blocks[1] = blocks[2] = blocks[3] =
+                    blocks[4] = blocks[5] = blocks[6] = blocks[7] =
+                        blocks[8] = blocks[9] = blocks[10] = blocks[11] =
+                            blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
+            }
+
+            if (ARRAY_BUFFER) {
+                for (i = this.start; index < length && i < 64; ++index) {
+                    code = message.charCodeAt(index);
+                    if (isBinStr || code < 0x80) {
+                        buffer8[i++] = code;
+                    } else if (code < 0x800) {
+                        buffer8[i++] = 0xc0 | (code >> 6);
+                        buffer8[i++] = 0x80 | (code & 0x3f);
+                    } else if (code < 0xd800 || code >= 0xe000) {
+                        buffer8[i++] = 0xe0 | (code >> 12);
+                        buffer8[i++] = 0x80 | ((code >> 6) & 0x3f);
+                        buffer8[i++] = 0x80 | (code & 0x3f);
+                    } else {
+                        code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
+                        buffer8[i++] = 0xf0 | (code >> 18);
+                        buffer8[i++] = 0x80 | ((code >> 12) & 0x3f);
+                        buffer8[i++] = 0x80 | ((code >> 6) & 0x3f);
+                        buffer8[i++] = 0x80 | (code & 0x3f);
+                    }
+                }
+            } else {
+                for (i = this.start; index < length && i < 64; ++index) {
+                    code = message.charCodeAt(index);
+                    if (isBinStr || code < 0x80) {
+                        blocks[i >> 2] |= code << SHIFT[i++ & 3];
+                    } else if (code < 0x800) {
+                        blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];
+                        blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
+                    } else if (code < 0xd800 || code >= 0xe000) {
+                        blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];
+                        blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
+                        blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
+                    } else {
+                        code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
+                        blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];
+                        blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];
+                        blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
+                        blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
+                    }
+                }
+            }
+            this.lastByteIndex = i;
+            this.bytes += i - this.start;
+            if (i >= 64) {
+                this.start = i - 64;
+                this.hash();
+                this.hashed = true;
+            } else {
+                this.start = i;
+            }
+        }
+        if (this.bytes > 4294967295) {
+            this.hBytes += this.bytes / 4294967296 << 0;
+            this.bytes = this.bytes % 4294967296;
+        }
+        return this;
+    };
+
+    Md5.prototype.finalize = function () {
+        if (this.finalized) {
+            return;
+        }
+        this.finalized = true;
+        var blocks = this.blocks, i = this.lastByteIndex;
+        blocks[i >> 2] |= EXTRA[i & 3];
+        if (i >= 56) {
+            if (!this.hashed) {
+                this.hash();
+            }
+            blocks[0] = blocks[16];
+            blocks[16] = blocks[1] = blocks[2] = blocks[3] =
+                blocks[4] = blocks[5] = blocks[6] = blocks[7] =
+                    blocks[8] = blocks[9] = blocks[10] = blocks[11] =
+                        blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
+        }
+        blocks[14] = this.bytes << 3;
+        blocks[15] = this.hBytes << 3 | this.bytes >>> 29;
+        this.hash();
+    };
+
+    Md5.prototype.hash = function () {
+        var a, b, c, d, bc, da, blocks = this.blocks;
+
+        if (this.first) {
+            a = blocks[0] - 680876937;
+            a = (a << 7 | a >>> 25) - 271733879 << 0;
+            d = (-1732584194 ^ a & 2004318071) + blocks[1] - 117830708;
+            d = (d << 12 | d >>> 20) + a << 0;
+            c = (-271733879 ^ (d & (a ^ -271733879))) + blocks[2] - 1126478375;
+            c = (c << 17 | c >>> 15) + d << 0;
+            b = (a ^ (c & (d ^ a))) + blocks[3] - 1316259209;
+            b = (b << 22 | b >>> 10) + c << 0;
+        } else {
+            a = this.h0;
+            b = this.h1;
+            c = this.h2;
+            d = this.h3;
+            a += (d ^ (b & (c ^ d))) + blocks[0] - 680876936;
+            a = (a << 7 | a >>> 25) + b << 0;
+            d += (c ^ (a & (b ^ c))) + blocks[1] - 389564586;
+            d = (d << 12 | d >>> 20) + a << 0;
+            c += (b ^ (d & (a ^ b))) + blocks[2] + 606105819;
+            c = (c << 17 | c >>> 15) + d << 0;
+            b += (a ^ (c & (d ^ a))) + blocks[3] - 1044525330;
+            b = (b << 22 | b >>> 10) + c << 0;
+        }
+
+        a += (d ^ (b & (c ^ d))) + blocks[4] - 176418897;
+        a = (a << 7 | a >>> 25) + b << 0;
+        d += (c ^ (a & (b ^ c))) + blocks[5] + 1200080426;
+        d = (d << 12 | d >>> 20) + a << 0;
+        c += (b ^ (d & (a ^ b))) + blocks[6] - 1473231341;
+        c = (c << 17 | c >>> 15) + d << 0;
+        b += (a ^ (c & (d ^ a))) + blocks[7] - 45705983;
+        b = (b << 22 | b >>> 10) + c << 0;
+        a += (d ^ (b & (c ^ d))) + blocks[8] + 1770035416;
+        a = (a << 7 | a >>> 25) + b << 0;
+        d += (c ^ (a & (b ^ c))) + blocks[9] - 1958414417;
+        d = (d << 12 | d >>> 20) + a << 0;
+        c += (b ^ (d & (a ^ b))) + blocks[10] - 42063;
+        c = (c << 17 | c >>> 15) + d << 0;
+        b += (a ^ (c & (d ^ a))) + blocks[11] - 1990404162;
+        b = (b << 22 | b >>> 10) + c << 0;
+        a += (d ^ (b & (c ^ d))) + blocks[12] + 1804603682;
+        a = (a << 7 | a >>> 25) + b << 0;
+        d += (c ^ (a & (b ^ c))) + blocks[13] - 40341101;
+        d = (d << 12 | d >>> 20) + a << 0;
+        c += (b ^ (d & (a ^ b))) + blocks[14] - 1502002290;
+        c = (c << 17 | c >>> 15) + d << 0;
+        b += (a ^ (c & (d ^ a))) + blocks[15] + 1236535329;
+        b = (b << 22 | b >>> 10) + c << 0;
+        a += (c ^ (d & (b ^ c))) + blocks[1] - 165796510;
+        a = (a << 5 | a >>> 27) + b << 0;
+        d += (b ^ (c & (a ^ b))) + blocks[6] - 1069501632;
+        d = (d << 9 | d >>> 23) + a << 0;
+        c += (a ^ (b & (d ^ a))) + blocks[11] + 643717713;
+        c = (c << 14 | c >>> 18) + d << 0;
+        b += (d ^ (a & (c ^ d))) + blocks[0] - 373897302;
+        b = (b << 20 | b >>> 12) + c << 0;
+        a += (c ^ (d & (b ^ c))) + blocks[5] - 701558691;
+        a = (a << 5 | a >>> 27) + b << 0;
+        d += (b ^ (c & (a ^ b))) + blocks[10] + 38016083;
+        d = (d << 9 | d >>> 23) + a << 0;
+        c += (a ^ (b & (d ^ a))) + blocks[15] - 660478335;
+        c = (c << 14 | c >>> 18) + d << 0;
+        b += (d ^ (a & (c ^ d))) + blocks[4] - 405537848;
+        b = (b << 20 | b >>> 12) + c << 0;
+        a += (c ^ (d & (b ^ c))) + blocks[9] + 568446438;
+        a = (a << 5 | a >>> 27) + b << 0;
+        d += (b ^ (c & (a ^ b))) + blocks[14] - 1019803690;
+        d = (d << 9 | d >>> 23) + a << 0;
+        c += (a ^ (b & (d ^ a))) + blocks[3] - 187363961;
+        c = (c << 14 | c >>> 18) + d << 0;
+        b += (d ^ (a & (c ^ d))) + blocks[8] + 1163531501;
+        b = (b << 20 | b >>> 12) + c << 0;
+        a += (c ^ (d & (b ^ c))) + blocks[13] - 1444681467;
+        a = (a << 5 | a >>> 27) + b << 0;
+        d += (b ^ (c & (a ^ b))) + blocks[2] - 51403784;
+        d = (d << 9 | d >>> 23) + a << 0;
+        c += (a ^ (b & (d ^ a))) + blocks[7] + 1735328473;
+        c = (c << 14 | c >>> 18) + d << 0;
+        b += (d ^ (a & (c ^ d))) + blocks[12] - 1926607734;
+        b = (b << 20 | b >>> 12) + c << 0;
+        bc = b ^ c;
+        a += (bc ^ d) + blocks[5] - 378558;
+        a = (a << 4 | a >>> 28) + b << 0;
+        d += (bc ^ a) + blocks[8] - 2022574463;
+        d = (d << 11 | d >>> 21) + a << 0;
+        da = d ^ a;
+        c += (da ^ b) + blocks[11] + 1839030562;
+        c = (c << 16 | c >>> 16) + d << 0;
+        b += (da ^ c) + blocks[14] - 35309556;
+        b = (b << 23 | b >>> 9) + c << 0;
+        bc = b ^ c;
+        a += (bc ^ d) + blocks[1] - 1530992060;
+        a = (a << 4 | a >>> 28) + b << 0;
+        d += (bc ^ a) + blocks[4] + 1272893353;
+        d = (d << 11 | d >>> 21) + a << 0;
+        da = d ^ a;
+        c += (da ^ b) + blocks[7] - 155497632;
+        c = (c << 16 | c >>> 16) + d << 0;
+        b += (da ^ c) + blocks[10] - 1094730640;
+        b = (b << 23 | b >>> 9) + c << 0;
+        bc = b ^ c;
+        a += (bc ^ d) + blocks[13] + 681279174;
+        a = (a << 4 | a >>> 28) + b << 0;
+        d += (bc ^ a) + blocks[0] - 358537222;
+        d = (d << 11 | d >>> 21) + a << 0;
+        da = d ^ a;
+        c += (da ^ b) + blocks[3] - 722521979;
+        c = (c << 16 | c >>> 16) + d << 0;
+        b += (da ^ c) + blocks[6] + 76029189;
+        b = (b << 23 | b >>> 9) + c << 0;
+        bc = b ^ c;
+        a += (bc ^ d) + blocks[9] - 640364487;
+        a = (a << 4 | a >>> 28) + b << 0;
+        d += (bc ^ a) + blocks[12] - 421815835;
+        d = (d << 11 | d >>> 21) + a << 0;
+        da = d ^ a;
+        c += (da ^ b) + blocks[15] + 530742520;
+        c = (c << 16 | c >>> 16) + d << 0;
+        b += (da ^ c) + blocks[2] - 995338651;
+        b = (b << 23 | b >>> 9) + c << 0;
+        a += (c ^ (b | ~d)) + blocks[0] - 198630844;
+        a = (a << 6 | a >>> 26) + b << 0;
+        d += (b ^ (a | ~c)) + blocks[7] + 1126891415;
+        d = (d << 10 | d >>> 22) + a << 0;
+        c += (a ^ (d | ~b)) + blocks[14] - 1416354905;
+        c = (c << 15 | c >>> 17) + d << 0;
+        b += (d ^ (c | ~a)) + blocks[5] - 57434055;
+        b = (b << 21 | b >>> 11) + c << 0;
+        a += (c ^ (b | ~d)) + blocks[12] + 1700485571;
+        a = (a << 6 | a >>> 26) + b << 0;
+        d += (b ^ (a | ~c)) + blocks[3] - 1894986606;
+        d = (d << 10 | d >>> 22) + a << 0;
+        c += (a ^ (d | ~b)) + blocks[10] - 1051523;
+        c = (c << 15 | c >>> 17) + d << 0;
+        b += (d ^ (c | ~a)) + blocks[1] - 2054922799;
+        b = (b << 21 | b >>> 11) + c << 0;
+        a += (c ^ (b | ~d)) + blocks[8] + 1873313359;
+        a = (a << 6 | a >>> 26) + b << 0;
+        d += (b ^ (a | ~c)) + blocks[15] - 30611744;
+        d = (d << 10 | d >>> 22) + a << 0;
+        c += (a ^ (d | ~b)) + blocks[6] - 1560198380;
+        c = (c << 15 | c >>> 17) + d << 0;
+        b += (d ^ (c | ~a)) + blocks[13] + 1309151649;
+        b = (b << 21 | b >>> 11) + c << 0;
+        a += (c ^ (b | ~d)) + blocks[4] - 145523070;
+        a = (a << 6 | a >>> 26) + b << 0;
+        d += (b ^ (a | ~c)) + blocks[11] - 1120210379;
+        d = (d << 10 | d >>> 22) + a << 0;
+        c += (a ^ (d | ~b)) + blocks[2] + 718787259;
+        c = (c << 15 | c >>> 17) + d << 0;
+        b += (d ^ (c | ~a)) + blocks[9] - 343485551;
+        b = (b << 21 | b >>> 11) + c << 0;
+
+        if (this.first) {
+            this.h0 = a + 1732584193 << 0;
+            this.h1 = b - 271733879 << 0;
+            this.h2 = c - 1732584194 << 0;
+            this.h3 = d + 271733878 << 0;
+            this.first = false;
+        } else {
+            this.h0 = this.h0 + a << 0;
+            this.h1 = this.h1 + b << 0;
+            this.h2 = this.h2 + c << 0;
+            this.h3 = this.h3 + d << 0;
+        }
+    };
+
+    /**
+     * @method hex
+     * @memberof Md5
+     * @instance
+     * @description Output hash as hex string
+     * @returns {String} Hex string
+     * @see {@link md5.hex}
+     * @example
+     * hash.hex();
+     */
+    Md5.prototype.hex = function () {
+        this.finalize();
+
+        var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3;
+
+        return HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] +
+            HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] +
+            HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] +
+            HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] +
+            HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] +
+            HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] +
+            HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] +
+            HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] +
+            HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] +
+            HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] +
+            HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] +
+            HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] +
+            HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] +
+            HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] +
+            HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] +
+            HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F];
+    };
+
+    /**
+     * @method toString
+     * @memberof Md5
+     * @instance
+     * @description Output hash as hex string
+     * @returns {String} Hex string
+     * @see {@link md5.hex}
+     * @example
+     * hash.toString();
+     */
+    Md5.prototype.toString = Md5.prototype.hex;
+
+    /**
+     * @method digest
+     * @memberof Md5
+     * @instance
+     * @description Output hash as bytes array
+     * @returns {Array} Bytes array
+     * @see {@link md5.digest}
+     * @example
+     * hash.digest();
+     */
+    Md5.prototype.digest = function (format) {
+        if (format === 'hex') return this.hex();
+        this.finalize();
+
+        var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3;
+        var res = [
+            h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 24) & 0xFF,
+            h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 24) & 0xFF,
+            h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 24) & 0xFF,
+            h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 24) & 0xFF
+        ];
+        return res;
+    };
+
+    /**
+     * @method array
+     * @memberof Md5
+     * @instance
+     * @description Output hash as bytes array
+     * @returns {Array} Bytes array
+     * @see {@link md5.array}
+     * @example
+     * hash.array();
+     */
+    Md5.prototype.array = Md5.prototype.digest;
+
+    /**
+     * @method arrayBuffer
+     * @memberof Md5
+     * @instance
+     * @description Output hash as ArrayBuffer
+     * @returns {ArrayBuffer} ArrayBuffer
+     * @see {@link md5.arrayBuffer}
+     * @example
+     * hash.arrayBuffer();
+     */
+    Md5.prototype.arrayBuffer = function () {
+        this.finalize();
+
+        var buffer = new ArrayBuffer(16);
+        var blocks = new Uint32Array(buffer);
+        blocks[0] = this.h0;
+        blocks[1] = this.h1;
+        blocks[2] = this.h2;
+        blocks[3] = this.h3;
+        return buffer;
+    };
+
+    /**
+     * @method buffer
+     * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead.
+     * @memberof Md5
+     * @instance
+     * @description Output hash as ArrayBuffer
+     * @returns {ArrayBuffer} ArrayBuffer
+     * @see {@link md5.buffer}
+     * @example
+     * hash.buffer();
+     */
+    Md5.prototype.buffer = Md5.prototype.arrayBuffer;
+
+    /**
+     * @method base64
+     * @memberof Md5
+     * @instance
+     * @description Output hash as base64 string
+     * @returns {String} base64 string
+     * @see {@link md5.base64}
+     * @example
+     * hash.base64();
+     */
+    Md5.prototype.base64 = function () {
+        var v1, v2, v3, base64Str = '', bytes = this.array();
+        for (var i = 0; i < 15;) {
+            v1 = bytes[i++];
+            v2 = bytes[i++];
+            v3 = bytes[i++];
+            base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] +
+                BASE64_ENCODE_CHAR[(v1 << 4 | v2 >>> 4) & 63] +
+                BASE64_ENCODE_CHAR[(v2 << 2 | v3 >>> 6) & 63] +
+                BASE64_ENCODE_CHAR[v3 & 63];
+        }
+        v1 = bytes[i];
+        base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] +
+            BASE64_ENCODE_CHAR[(v1 << 4) & 63] +
+            '==';
+        return base64Str;
+    };
+
+    var exports = createMethod();
+
+    if (COMMON_JS) {
+        module.exports = exports;
+    } else {
+        /**
+         * @method md5
+         * @description Md5 hash function, export to global in browsers.
+         * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash
+         * @returns {String} md5 hashes
+         * @example
+         * md5(''); // d41d8cd98f00b204e9800998ecf8427e
+         * md5('The quick brown fox jumps over the lazy dog'); // 9e107d9d372bb6826bd81d3542a419d6
+         * md5('The quick brown fox jumps over the lazy dog.'); // e4d909c290d0fb1ca068ffaddf22cbd0
+         *
+         * // It also supports UTF-8 encoding
+         * md5('中文'); // a7bac2239fcdcb3a067903d8077c4a07
+         *
+         * // It also supports byte `Array`, `Uint8Array`, `ArrayBuffer`
+         * md5([]); // d41d8cd98f00b204e9800998ecf8427e
+         * md5(new Uint8Array([])); // d41d8cd98f00b204e9800998ecf8427e
+         */
+        root.md5 = exports;
+        if (AMD) {
+            define(function () {
+                return exports;
+            });
+        }
+    }
+})();

+ 139 - 0
node_modules/cos-js-sdk-v5/lib/request.js

@@ -0,0 +1,139 @@
+var stringifyPrimitive = function(v) {
+    switch (typeof v) {
+        case 'string':
+            return v;
+        case 'boolean':
+            return v ? 'true' : 'false';
+        case 'number':
+            return isFinite(v) ? v : '';
+        default:
+            return '';
+    }
+};
+
+var queryStringify = function(obj, sep, eq, name) {
+    sep = sep || '&';
+    eq = eq || '=';
+    if (obj === null) {
+        obj = undefined;
+    }
+    if (typeof obj === 'object') {
+        return Object.keys(obj).map(function(k) {
+            var ks = encodeURIComponent(stringifyPrimitive(k)) + eq;
+            if (Array.isArray(obj[k])) {
+                return obj[k].map(function(v) {
+                    return ks + encodeURIComponent(stringifyPrimitive(v));
+                }).join(sep);
+            } else {
+                return ks + encodeURIComponent(stringifyPrimitive(obj[k]));
+            }
+        }).filter(Boolean).join(sep);
+
+    }
+    if (!name) return '';
+    return encodeURIComponent(stringifyPrimitive(name)) + eq +
+        encodeURIComponent(stringifyPrimitive(obj));
+};
+
+var xhrRes = function (err, xhr, body) {
+    var headers = {};
+    var strHeaders = xhr.getAllResponseHeaders();
+    if (strHeaders && strHeaders.length > 0) {
+        strHeaders.trim().split('\n').forEach(function (item) {
+            if (item) {
+                var index = item.indexOf(':');
+                var key = item.substr(0, index).trim().toLowerCase();
+                var val = item.substr(index + 1).trim();
+                headers[key] = val;
+            }
+        });
+    }
+    return {
+        error: err,
+        statusCode: xhr.status,
+        statusMessage: xhr.statusText,
+        headers: headers,
+        body: body,
+    };
+};
+
+var xhrBody = function (xhr, dataType) {
+    return !dataType && dataType === 'text' ? xhr.responseText : xhr.response;
+};
+
+var request = function (opt, callback) {
+
+    // method
+    var method = (opt.method || 'GET').toUpperCase();
+
+    // url、qs
+    var url = opt.url;
+    if (opt.qs) {
+        var qsStr = queryStringify(opt.qs);
+        if (qsStr) {
+            url += (url.indexOf('?') === -1 ? '?' : '&') + qsStr;
+        }
+    }
+
+    // 创建 ajax 实例
+    var xhr = new XMLHttpRequest();
+    xhr.open(method, url, true);
+    xhr.responseType = opt.dataType || 'text';
+
+    // 处理 xhrFields 属性
+    if (opt.xhrFields) {
+        for (var xhrField in opt.xhrFields) {
+            xhr[xhrField] = opt.xhrFields[xhrField]
+        }
+    }
+
+    // 处理 headers
+    var headers = opt.headers;
+    if (headers) {
+        for (var key in headers) {
+            if (headers.hasOwnProperty(key) &&
+                key.toLowerCase() !== 'content-length' &&
+                key.toLowerCase() !== 'user-agent' &&
+                key.toLowerCase() !== 'origin' &&
+                key.toLowerCase() !== 'host') {
+                xhr.setRequestHeader(key, headers[key]);
+            }
+        }
+    }
+
+    // onprogress
+    if (opt.onProgress && xhr.upload) xhr.upload.onprogress = opt.onProgress;
+    if (opt.onDownloadProgress) xhr.onprogress = opt.onDownloadProgress;
+
+    // timeout
+    if (opt.timeout) xhr.timeout = opt.timeout;
+    xhr.ontimeout = function(event){
+        var error = new Error('timeout');
+        callback(xhrRes(error, xhr));
+    };
+
+    // success 2xx/3xx/4xx
+    xhr.onload = function () {
+        callback(xhrRes(null, xhr, xhrBody(xhr, opt.dataType)));
+    };
+
+    // error 5xx/0 (网络错误、跨域报错、Https connect-src 限制的报错时 statusCode 为 0)
+    xhr.onerror = function (err) {
+        var body = xhrBody(xhr, opt.dataType);
+        if (body) { // 5xx
+            callback(xhrRes(null, xhr, body));
+        } else { // 0
+            var error = xhr.statusText;
+            if (!error && xhr.status === 0) error = new Error('CORS blocked or network error');
+            callback(xhrRes(error, xhr, body));
+        }
+    };
+
+    // send
+    xhr.send(opt.body || '');
+
+    // 返回 ajax 实例,用于外部调用 xhr.abort
+    return xhr;
+};
+
+module.exports = request;

+ 166 - 0
node_modules/cos-js-sdk-v5/lib/xml2json.js

@@ -0,0 +1,166 @@
+/* Copyright 2015 William Summers, MetaTribal LLC
+ * adapted from https://developer.mozilla.org/en-US/docs/JXON
+ *
+ * Licensed under the MIT 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
+ *
+ *     https://opensource.org/licenses/MIT
+ *
+ * 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.
+ */
+/**
+ * @author William Summers
+ * https://github.com/metatribal/xmlToJSON
+ */
+var DOMParser = require('@xmldom/xmldom').DOMParser;
+
+var xmlToJSON = (function () {
+
+    this.version = "1.3.5";
+
+    var options = { // set up the default options
+        mergeCDATA: true, // extract cdata and merge with text
+        normalize: true, // collapse multiple spaces to single space
+        stripElemPrefix: true, // for elements of same name in diff namespaces, you can enable namespaces and access the nskey property
+    };
+
+    var prefixMatch = new RegExp(/(?!xmlns)^.*:/);
+    var trimMatch = new RegExp(/^\s+|\s+$/g);
+
+    this.grokType = function (sValue) {
+        if (/^\s*$/.test(sValue)) {
+            return null;
+        }
+        if (/^(?:true|false)$/i.test(sValue)) {
+            return sValue.toLowerCase() === "true";
+        }
+        if (isFinite(sValue)) {
+            return parseFloat(sValue);
+        }
+        return sValue;
+    };
+
+    this.parseString = function (xmlString, opt) {
+        if (xmlString) {
+            var xml = this.stringToXML(xmlString);
+            if (xml.getElementsByTagName('parsererror').length) {
+                return null;
+            } else {
+                return this.parseXML(xml, opt);
+            }
+        } else {
+            return null;
+        }
+    };
+
+    this.parseXML = function (oXMLParent, opt) {
+
+        // initialize options
+        for (var key in opt) {
+            options[key] = opt[key];
+        }
+
+        var vResult = {},
+            nLength = 0,
+            sCollectedTxt = "";
+
+        // iterate over the children
+        var childNum = oXMLParent.childNodes.length;
+        if (childNum) {
+            for (var oNode, sProp, vContent, nItem = 0; nItem < oXMLParent.childNodes.length; nItem++) {
+                oNode = oXMLParent.childNodes.item(nItem);
+
+                if (oNode.nodeType === 4) {
+                    if (options.mergeCDATA) {
+                        sCollectedTxt += oNode.nodeValue;
+                    }
+                } /* nodeType is "CDATASection" (4) */
+                else if (oNode.nodeType === 3) {
+                    sCollectedTxt += oNode.nodeValue;
+                } /* nodeType is "Text" (3) */
+                else if (oNode.nodeType === 1) { /* nodeType is "Element" (1) */
+
+                    if (nLength === 0) {
+                        vResult = {};
+                    }
+
+                    // using nodeName to support browser (IE) implementation with no 'localName' property
+                    if (options.stripElemPrefix) {
+                        sProp = oNode.nodeName.replace(prefixMatch, '');
+                    } else {
+                        sProp = oNode.nodeName;
+                    }
+
+                    vContent = xmlToJSON.parseXML(oNode);
+
+                    if (vResult.hasOwnProperty(sProp)) {
+                        if (vResult[sProp].constructor !== Array) {
+                            vResult[sProp] = [vResult[sProp]];
+                        }
+                        vResult[sProp].push(vContent);
+
+                    } else {
+                        vResult[sProp] = vContent;
+                        nLength++;
+                    }
+                }
+            }
+        }
+
+        if (!Object.keys(vResult).length) {
+            // vResult = sCollectedTxt.replace(trimMatch, '') || ''; // by carsonxu 修复 getBucket返回的 Key 是 " /" 这种场景
+            vResult = sCollectedTxt || '';
+        }
+
+        return vResult;
+    };
+
+    // Convert xmlDocument to a string
+    // Returns null on failure
+    this.xmlToString = function (xmlDoc) {
+        try {
+            var xmlString = xmlDoc.xml ? xmlDoc.xml : (new XMLSerializer()).serializeToString(xmlDoc);
+            return xmlString;
+        } catch (err) {
+            return null;
+        }
+    };
+
+    // Convert a string to XML Node Structure
+    // Returns null on failure
+    this.stringToXML = function (xmlString) {
+        try {
+            var xmlDoc = null;
+
+            if (window.DOMParser) {
+
+                var parser = new DOMParser();
+                xmlDoc = parser.parseFromString(xmlString, "text/xml");
+
+                return xmlDoc;
+            } else {
+                xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
+                xmlDoc.async = false;
+                xmlDoc.loadXML(xmlString);
+
+                return xmlDoc;
+            }
+        } catch (e) {
+            return null;
+        }
+    };
+
+    return this;
+
+}).call({});
+
+var xml2json = function (xmlString) {
+    return xmlToJSON.parseString(xmlString);
+};
+
+module.exports = xml2json;

+ 47 - 0
node_modules/cos-js-sdk-v5/package.json

@@ -0,0 +1,47 @@
+{
+  "name": "cos-js-sdk-v5",
+  "version": "1.5.0",
+  "description": "JavaScript SDK for [腾讯云对象存储](https://cloud.tencent.com/product/cos)",
+  "main": "dist/cos-js-sdk-v5.js",
+  "types": "index.d.ts",
+  "scripts": {
+    "prettier": "prettier --write src demo/demo.js demo/CIDemos/*.js test/test.js server/sts.js index.d.ts",
+    "server": "node server/sts.js",
+    "dev": "cross-env NODE_ENV=development webpack -w --mode=development",
+    "build": "cross-env NODE_ENV=production webpack --mode=production",
+    "cos-auth.min.js": "uglifyjs ./demo/common/cos-auth.js -o ./demo/common/cos-auth.min.js -c -m",
+    "test": "jest --runInBand --coverage"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/tencentyun/cos-js-sdk-v5.git"
+  },
+  "keywords": [],
+  "author": "carsonxu",
+  "license": "ISC",
+  "bugs": {
+    "url": "https://github.com/tencentyun/cos-js-sdk-v5/issues"
+  },
+  "homepage": "https://github.com/tencentyun/cos-js-sdk-v5#readme",
+  "dependencies": {
+    "@xmldom/xmldom": "^0.8.6"
+  },
+  "devDependencies": {
+    "@babel/core": "7.17.9",
+    "@babel/plugin-transform-runtime": "7.18.10",
+    "@babel/preset-env": "7.16.11",
+    "babel-loader": "8.2.5",
+    "body-parser": "^1.18.3",
+    "cross-env": "^5.2.0",
+    "express": "^4.16.4",
+    "jest": "^29.3.1",
+    "jest-environment-jsdom": "^29.3.1",
+    "prettier": "^3.0.1",
+    "qcloud-cos-sts": "^3.0.2",
+    "request": "^2.87.0",
+    "terser-webpack-plugin": "4.2.3",
+    "uglifyjs": "^2.4.11",
+    "webpack": "4.46.0",
+    "webpack-cli": "4.10.0"
+  }
+}

+ 171 - 0
node_modules/cos-js-sdk-v5/server/qcloud-sts-sdk.php

@@ -0,0 +1,171 @@
+<?php
+
+/**
+ * 代码出处:
+ * https://github.com/tencentyun/qcloud-cos-sts-sdk
+ */
+
+class STS{
+    // 临时密钥计算样例
+
+    function _hex2bin($data) {
+        $len = strlen($data);
+        return pack("H" . $len, $data);
+    }
+    // obj 转 query string
+    function json2str($obj, $notEncode = false) {
+        ksort($obj);
+        $arr = array();
+        if(!is_array($obj)){
+            throw new Exception($obj + " must be a array");
+        }
+        foreach ($obj as $key => $val) {
+            array_push($arr, $key . '=' . ($notEncode ? $val : rawurlencode($val)));
+        }
+        return join('&', $arr);
+    }
+    // 计算临时密钥用的签名
+    function getSignature($opt, $key, $method, $config) {
+        $formatString = $method . $config['domain'] . '/?' . $this->json2str($opt, 1);
+        $sign = hash_hmac('sha1', $formatString, $key);
+        $sign = base64_encode($this->_hex2bin($sign));
+        return $sign;
+    }
+    // v2接口的key首字母小写,v3改成大写,此处做了向下兼容
+    function backwardCompat($result) {
+        if(!is_array($result)){
+            throw new Exception($result + " must be a array");
+        }
+        $compat = array();
+        foreach ($result as $key => $value) {
+            if(is_array($value)) {
+                $compat[lcfirst($key)] = $this->backwardCompat($value);
+            } elseif ($key == 'Token') {
+                $compat['sessionToken'] = $value;
+            } else {
+                $compat[lcfirst($key)] = $value;
+            }
+        }
+        return $compat;
+    }
+    // 获取临时密钥
+    function getTempKeys($config) {
+        if(array_key_exists('bucket', $config)){
+            $ShortBucketName = substr($config['bucket'],0, strripos($config['bucket'], '-'));
+            $AppId = substr($config['bucket'], 1 + strripos($config['bucket'], '-'));
+        }
+        if(array_key_exists('policy', $config)){
+            $policy = $config['policy'];
+        }else{
+            $policy = array(
+                'version'=> '2.0',
+                'statement'=> array(
+                    array(
+                        'action'=> $config['allowActions'],
+                        'effect'=> 'allow',
+                        'principal'=> array('qcs'=> array('*')),
+                        'resource'=> array(
+                            'qcs::cos:' . $config['region'] . ':uid/' . $AppId . ':prefix//' . $AppId . '/' . $ShortBucketName . '/' . $config['allowPrefix']
+                        )
+                    )
+                )
+            );
+        }
+        $policyStr = str_replace('\\/', '/', json_encode($policy));
+        $Action = 'GetFederationToken';
+        $Nonce = rand(10000, 20000);
+        $Timestamp = time();
+        $Method = 'POST';
+        $params = array(
+            'SecretId'=> $config['secretId'],
+            'Timestamp'=> $Timestamp,
+            'Nonce'=> $Nonce,
+            'Action'=> $Action,
+            'DurationSeconds'=> $config['durationSeconds'],
+            'Version'=>'2018-08-13',
+            'Name'=> 'cos',
+            'Region'=> 'ap-guangzhou',
+            'Policy'=> urlencode($policyStr)
+        );
+        $params['Signature'] = $this->getSignature($params, $config['secretKey'], $Method, $config);
+        $url = $config['url'];
+        $ch = curl_init($url);
+        if(array_key_exists('proxy', $config)){
+            $config['proxy'] && curl_setopt($ch, CURLOPT_PROXY, $config['proxy']);
+        }
+        curl_setopt($ch, CURLOPT_HEADER, 0);
+        curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,0);
+        curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,0);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+        curl_setopt($ch, CURLOPT_POST, 1);
+        curl_setopt($ch, CURLOPT_POSTFIELDS, $this->json2str($params));
+        $result = curl_exec($ch);
+        if(curl_errno($ch)) $result = curl_error($ch);
+        curl_close($ch);
+        $result = json_decode($result, 1);
+        if (isset($result['Response'])) {
+            $result = $result['Response'];
+            $result['startTime'] = $result['ExpiredTime'] - $config['durationSeconds'];
+        }
+        $result = $this->backwardCompat($result);
+        return $result;
+    }
+
+    // get policy
+    function getPolicy($scopes){
+        if (!is_array($scopes)){
+            return null;
+        }
+        $statements = array();
+
+        for($i=0, $counts=count($scopes); $i < $counts; $i++){
+            $actions=array();
+            $resources = array();
+            array_push($actions, $scopes[$i]->get_action());
+            array_push($resources, $scopes[$i]->get_resource());
+            $principal = array(
+                'qcs' => array('*')
+            );
+            $statement = array(
+                'actions' => $actions,
+                'effect' => 'allow',
+                'principal' => $principal,
+                'resource' => $resources
+            );
+            array_push($statements, $statement);
+        }
+
+        $policy = array(
+            'version' => '2.0',
+            'statement' => $statements
+        );
+        return $policy;
+    }
+}
+
+class Scope{
+    var $action;
+    var $bucket;
+    var $region;
+    var $resourcePrefix;
+    function __construct($action, $bucket, $region, $resourcePrefix){
+        $this->action = $action;
+        $this->bucket = $bucket;
+        $this->region = $region;
+        $this->resourcePrefix = $resourcePrefix;
+    }
+    function get_action(){
+        return $this->action;
+    }
+
+    function get_resource(){
+        $index = strripos($this->bucket, '-');
+        $bucketName = substr($this->bucket, 0, $index);
+        $appid = substr($this->bucket, $index + 1);
+        if(!(strpos($this->resourcePrefix, '/') === 0)){
+            $this->resourcePrefix = '/' . $this->resourcePrefix;
+        }
+        return 'qcs::cos:' . $this->region . ':uid/' . $appid . ':prefix//' . $appid . '/' . $bucketName . $this->resourcePrefix;
+    }
+}
+?>

+ 480 - 0
node_modules/cos-js-sdk-v5/server/sts.js

@@ -0,0 +1,480 @@
+// 临时密钥服务例子
+var bodyParser = require('body-parser');
+var STS = require('qcloud-cos-sts');
+var express = require('express');
+var crypto = require('crypto');
+var pathLib = require('path');
+var fs = require('fs');
+
+// 配置参数
+var config = {
+  secretId: process.env.SecretId,
+  secretKey: process.env.SecretKey,
+  proxy: process.env.Proxy,
+  durationSeconds: 1800,
+  bucket: process.env.Bucket,
+  region: process.env.Region,
+  // 允许操作(上传)的对象前缀,可以根据自己网站的用户登录态判断允许上传的目录,例子: user1/* 或者 * 或者a.jpg
+  // 请注意当使用 * 时,可能存在安全风险,详情请参阅:https://cloud.tencent.com/document/product/436/40265
+  allowPrefix: '_ALLOW_DIR_/*',
+  // 密钥的权限列表
+  allowActions: [
+    // 所有 action 请看文档
+    // COS actions: https://cloud.tencent.com/document/product/436/31923
+    // CI actions: https://cloud.tencent.com/document/product/460/41741
+    // 简单上传
+    'name/cos:PutObject',
+    'name/cos:PostObject',
+    // 分片上传
+    'name/cos:InitiateMultipartUpload',
+    'name/cos:ListMultipartUploads',
+    'name/cos:ListParts',
+    'name/cos:UploadPart',
+    'name/cos:CompleteMultipartUpload',
+    // 下载文件
+    'name/cos:GetObject',
+    // 文本审核任务
+    'ci:CreateAuditingTextJob',
+  ],
+  // condition条件限定,关于 condition 的详细设置规则和COS支持的condition类型可以参考https://cloud.tencent.com/document/product/436/71306
+  // condition:{
+  //   // 比如限制该ip才能访问cos
+  //   'ip_equal': {
+  //       'qcs:ip': '192.168.1.1'
+  //   },
+  // 比如限制上传文件最大为1MB
+  //   'numeric_less_than_equal: {
+  //     'cos:content-length': 1038336
+  // }
+  // }
+  // 限制的上传后缀
+  extWhiteList: ['jpg', 'jpeg', 'png', 'gif', 'bmp'],
+};
+
+function camSafeUrlEncode(str) {
+  return encodeURIComponent(str)
+    .replace(/!/g, '%21')
+    .replace(/'/g, '%27')
+    .replace(/\(/g, '%28')
+    .replace(/\)/g, '%29')
+    .replace(/\*/g, '%2A');
+}
+
+var getObjectKeys = function (obj, forKey) {
+  var list = [];
+  for (var key in obj) {
+    if (obj.hasOwnProperty(key)) {
+      list.push(forKey ? camSafeUrlEncode(key).toLowerCase() : key);
+    }
+  }
+  return list.sort(function (a, b) {
+    a = a.toLowerCase();
+    b = b.toLowerCase();
+    return a === b ? 0 : a > b ? 1 : -1;
+  });
+};
+
+/**
+ * obj转为string
+ * @param  {Object}  obj                需要转的对象,必须
+ * @param  {Boolean} lowerCaseKey       key是否转为小写,默认false,非必须
+ * @return {String}  data               返回字符串
+ */
+var obj2str = function (obj, lowerCaseKey) {
+  var i, key, val;
+  var list = [];
+  var keyList = getObjectKeys(obj);
+  for (i = 0; i < keyList.length; i++) {
+    key = keyList[i];
+    val = obj[key] === undefined || obj[key] === null ? '' : '' + obj[key];
+    key = lowerCaseKey ? camSafeUrlEncode(key).toLowerCase() : camSafeUrlEncode(key);
+    val = camSafeUrlEncode(val) || '';
+    list.push(key + '=' + val);
+  }
+  return list.join('&');
+};
+
+// 生成要上传的 COS 文件路径文件名
+var generateCosKey = function (ext) {
+  var date = new Date();
+  var m = date.getMonth() + 1;
+  var ymd = `${date.getFullYear()}${m < 10 ? `0${m}` : m}${date.getDate()}`;
+  var r = ('000000' + Math.random() * 1000000).slice(-6);
+  var cosKey = `file/${ymd}/${ymd}_${r}${ext ? `.${ext}` : ''}`;
+  return cosKey;
+};
+var cosHost = `${config.bucket}.cos.${config.region}.myqcloud.com`;
+
+// 创建临时密钥服务和用于调试的静态服务
+var app = express();
+
+var replaceBucketRegion = (filePath) => {
+  return (req, res, next) => {
+    var content = fs
+      .readFileSync(filePath)
+      .toString()
+      .replace(
+        /(var config = {\r?\n *Bucket: ')test-1250000000(',\r?\n *Region: ')ap-guangzhou(')/,
+        '$1' + config.bucket + '$2' + config.region + '$3'
+      );
+    if (process.env.Uin) {
+      content = content
+        .replace("config.Uin = '10001';", "config.Uin = '" + process.env.Uin + "'")
+        .replace("Uin: '10001'", "Uin: '" + process.env.Uin + "'");
+    }
+    res.header('Content-Type', 'application/javascript');
+    res.send(content);
+  };
+};
+
+app.use(function (req, res, next) {
+  res.header('Access-Control-Allow-Origin', '*');
+  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
+  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
+  next();
+});
+
+app.use('/demo/demo.js', replaceBucketRegion(pathLib.resolve(__dirname, '../demo/demo.js')));
+app.use('/test/test.js', replaceBucketRegion(pathLib.resolve(__dirname, '../test/test.js')));
+app.use('/dist/', express.static(pathLib.resolve(__dirname, '../dist')));
+app.use('/demo/', express.static(pathLib.resolve(__dirname, '../demo')));
+app.use('/test/', express.static(pathLib.resolve(__dirname, '../test')));
+app.all('/', (req, res, next) => res.redirect('/demo/'));
+app.use(bodyParser.json());
+
+// 获取临时密钥
+function getSts() {
+  return new Promise((resolve, reject) => {
+    // 获取临时密钥
+    var AppId = config.bucket.substr(config.bucket.lastIndexOf('-') + 1);
+    // 数据万象DescribeMediaBuckets接口需要resource为*,参考 https://cloud.tencent.com/document/product/460/41741
+    var policy = {
+      version: '2.0',
+      statement: [
+        {
+          action: config.allowActions,
+          effect: 'allow',
+          resource: [
+            // cos相关授权路径
+            'qcs::cos:' + config.region + ':uid/' + AppId + ':' + config.bucket + '/' + config.allowPrefix,
+            // ci相关授权路径 按需使用
+            'qcs::ci:' + config.region + ':uid/' + AppId + ':bucket/' + config.bucket + '/' + 'job/*',
+          ],
+        },
+      ],
+    };
+    var startTime = Math.round(Date.now() / 1000);
+    STS.getCredential(
+      {
+        secretId: config.secretId,
+        secretKey: config.secretKey,
+        proxy: config.proxy,
+        region: config.region,
+        durationSeconds: config.durationSeconds,
+        // endpoint: 'sts.internal.tencentcloudapi.com', // 支持设置sts内网域名
+        policy: policy,
+      },
+      function (err, tempKeys) {
+        if (tempKeys) tempKeys.startTime = startTime;
+        if (err) {
+          reject(err);
+        } else {
+          resolve(tempKeys);
+        }
+      }
+    );
+  });
+}
+
+// 返回临时密钥,客户端自行计算签名
+app.all('/sts', function (req, res, next) {
+  // TODO 这里根据自己业务需要做好放行判断
+  if (config.allowPrefix === '_ALLOW_DIR_/*') {
+    res.send({ error: '请修改 allowPrefix 配置项,指定允许上传的路径前缀' });
+    return;
+  }
+  getSts()
+    .then((data) => {
+      res.send(data);
+    })
+    .catch((err) => {
+      res.send(err);
+    });
+});
+
+// // 格式二:临时密钥接口,支持细粒度权限控制
+// // 判断是否允许获取密钥
+// var allowScope = function (scope) {
+//     var allow = (scope || []).every(function (item) {
+//         return config.allowActions.includes(item.action) &&
+//             item.bucket === config.bucket &&
+//             item.region === config.region &&
+//             (item.prefix || '').startsWith(config.allowPrefix);
+//     });
+//     return allow;
+// };
+// app.all('/sts-scope', function (req, res, next) {
+//     var scope = req.body;
+//
+//     // TODO 这里根据自己业务需要做好放行判断
+//     if (config.allowPrefix === '_ALLOW_DIR_/*') {
+//         res.send({error: '请修改 allowPrefix 配置项,指定允许上传的路径前缀'});
+//         return;
+//     }
+//     // TODO 这里可以判断 scope 细粒度控制权限
+//     if (!scope || !scope.length || !allowScope(scope)) return res.send({error: 'deny'});
+//
+//     // 获取临时密钥
+//     var policy = STS.getPolicy(scope);
+//     var startTime = Math.round(Date.now() / 1000);
+//     STS.getCredential({
+//         secretId: config.secretId,
+//         secretKey: config.secretKey,
+//         proxy: config.proxy,
+//         durationSeconds: config.durationSeconds,
+//         policy: policy,
+//     }, function (err, tempKeys) {
+//         if (tempKeys) tempKeys.startTime = startTime;
+//         res.send(err || tempKeys);
+//     });
+// });
+//
+
+// 生成put上传签名,客户端传递文件后缀,这里生成随机Key
+app.all('/put-sign', async function (req, res, next) {
+  var ext = req.query.ext;
+
+  // 判断异常情况
+  if (!config.secretId || !config.secretKey)
+    return res.send({ code: '-1', message: 'secretId or secretKey not ready' });
+  if (!config.bucket || !config.region) return res.send({ code: '-1', message: 'bucket or regions not ready' });
+  // if (!config.extWhiteList.includes(ext)) return res.send({code: '-1', message: 'ext not allow'});
+
+  var cosKey = generateCosKey(ext);
+
+  let ak = config.secretId;
+  let sk = config.secretKey;
+  let securityToken = '';
+
+  // 也可以使用临时密钥计算签名,使用临时密钥计算时 前端上传文件时必须上送securityToken字段
+  // try {
+  //   const tmpData = await getSts();
+  //   ak = tmpData.credentials.tmpSecretId;
+  //   sk = tmpData.credentials.tmpSecretKey;
+  //   securityToken = tmpData.credentials.sessionToken;
+  // } catch (e) {
+  //   console.log('get sts error', e);
+  // }
+
+  // 开始计算签名
+  var qSignAlgorithm = 'sha1';
+  var method = 'put';
+  var pathname = cosKey;
+  pathname.indexOf('/') !== 0 && (pathname = '/' + pathname);
+  var qAk = ak;
+  var now = Math.round(new Date().getTime() / 1000) - 1;
+  var exp = now + 900; // 默认900s过期
+  var qSignTime = now + ';' + exp;
+  var qKeyTime = now + ';' + exp;
+  var queryParams = {};
+  var headers = {
+    host: cosHost,
+  };
+  var qHeaderList = getObjectKeys(headers, true).join(';').toLowerCase();
+  var qUrlParamList = getObjectKeys(queryParams, true).join(';').toLowerCase();
+
+  // 签名算法说明文档:https://www.qcloud.com/document/product/436/7778
+  // 步骤一:计算 SignKey
+  var signKey = crypto.createHmac('sha1', sk).update(qKeyTime).digest('hex');
+
+  // 步骤二:构成 FormatString
+  var formatString = [method, pathname, obj2str(queryParams, true), obj2str(headers, true), ''].join('\n');
+  formatString = Buffer.from(formatString, 'utf8');
+
+  // 步骤三:计算 StringToSign
+  var r = crypto.createHash('sha1').update(formatString).digest('hex');
+  var stringToSign = ['sha1', qSignTime, r, ''].join('\n');
+
+  // 步骤四:计算 Signature
+  var qSignature = crypto.createHmac('sha1', signKey).update(stringToSign).digest('hex');
+
+  // 步骤五:构造 Authorization
+  var authorization = [
+    'q-sign-algorithm=' + qSignAlgorithm,
+    'q-ak=' + qAk,
+    'q-sign-time=' + qSignTime,
+    'q-key-time=' + qKeyTime,
+    'q-header-list=' + qHeaderList,
+    'q-url-param-list=' + qUrlParamList,
+    'q-signature=' + qSignature,
+  ].join('&');
+
+  res.send({
+    cosHost,
+    cosKey,
+    authorization,
+    securityToken: securityToken, // 如果使用临时密钥,要返回在这个资源 sessionToken 的值
+  });
+});
+
+// 生成post上传签名,客户端传递文件后缀,这里生成随机Key
+app.all('/post-policy', async function (req, res, next) {
+  var query = req.query;
+  var ext = query.ext;
+
+  // 判断异常情况
+  if (!config.secretId || !config.secretKey)
+    return res.send({ code: '-1', message: 'secretId or secretKey not ready' });
+  if (!config.bucket || !config.region) return res.send({ code: '-1', message: 'bucket or regions not ready' });
+  // if (!config.extWhiteList.includes(ext)) return res.send({code: '-1', message: 'ext not allow'});
+
+  // 服务端生成随机Key并计算签名
+  var cosKey = generateCosKey(ext);
+
+  let ak = config.secretId;
+  let sk = config.secretKey;
+  let securityToken = '';
+
+  // 也可以使用临时密钥计算签名,使用临时密钥计算时 前端上传文件时必须上送securityToken字段
+  // try {
+  //   const tmpData = await getSts();
+  //   ak = tmpData.credentials.tmpSecretId;
+  //   sk = tmpData.credentials.tmpSecretKey;
+  //   securityToken = tmpData.credentials.sessionToken;
+  // } catch (e) {
+  //   console.log('get sts error', e);
+  // }
+
+  var now = Math.round(Date.now() / 1000);
+  var exp = now + 900;
+  var qKeyTime = now + ';' + exp;
+  var qSignAlgorithm = 'sha1';
+  var policy = JSON.stringify({
+    expiration: new Date(exp * 1000).toISOString(),
+    conditions: [
+      // {'acl': query.ACL},
+      // ['starts-with', '$Content-Type', 'image/'],
+      // ['starts-with', '$success_action_redirect', redirectUrl],
+      // ['eq', '$x-cos-server-side-encryption', 'AES256'],
+      // ['content-length-range', 1, 5242880 ], // 可限制上传文件大小范围比如1 - 5MB
+      { 'q-sign-algorithm': qSignAlgorithm },
+      { 'q-ak': ak },
+      { 'q-sign-time': qKeyTime },
+      { bucket: config.bucket },
+      { key: cosKey },
+    ],
+  });
+
+  // 签名算法说明文档:https://www.qcloud.com/document/product/436/7778
+  // 步骤一:生成 SignKey
+  var signKey = crypto.createHmac('sha1', sk).update(qKeyTime).digest('hex');
+
+  // 步骤二:生成 StringToSign
+  var stringToSign = crypto.createHash('sha1').update(policy).digest('hex');
+
+  // 步骤三:生成 Signature
+  var qSignature = crypto.createHmac('sha1', signKey).update(stringToSign).digest('hex');
+
+  res.send({
+    cosHost,
+    cosKey,
+    policyObj: JSON.parse(policy),
+    policy: Buffer.from(policy).toString('base64'),
+    qSignAlgorithm: qSignAlgorithm,
+    qAk: ak,
+    qKeyTime: qKeyTime,
+    qSignature: qSignature,
+    securityToken: securityToken, // 如果使用临时密钥,要返回在这个资源 sessionToken 的值
+  });
+});
+
+//
+// // 上传限制 Content-Type 示例,对应示例 demo/mime-limit.html
+// var COS = require('cos-nodejs-sdk-v5');
+// var cos = new COS({
+//     SecretId: config.secretId,
+//     SecretKey: config.secretKey,
+// });
+// app.post('/uploadSign', function (req, res, next) {
+//
+//     var T = function (x, n) {
+//         return ('0000' + x).slice(-(n || 2));
+//     }
+//     var guid = function () {
+//         var S4 = () => (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
+//         return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
+//     }
+//
+//     // 后端来决定文件名,安全性更高
+//     var filename = req.query.filename; // 前端传文件原名,后端来决定上传路径
+//     var ext = pathLib.extname(filename);
+//     var d = new Date();
+//     var key = `images/${d.getFullYear()}/${T(d.getMonth() + 1)}/${T(d.getDate())}/${guid()}${ext}`;
+//
+//     // 计算前端可能会用到的多个签名,x-cos-mime-limit: text/plain;img/jpg;img/*
+//     var signMap = {};
+//     var expires = 7200;
+//     var mimeLimit = 'image/*';
+//     var host = `${config.bucket}.cos.${config.region}.myqcloud.com`;
+//     // 1. ListMultipartUploads 签名
+//     signMap.ListMultipartUploads = cos.getAuth({
+//         Method: 'GET',
+//         Key: '',
+//         Expires: expires,
+//         Query: { uploads: '', prefix: key },
+//         Headers: { host: host },
+//     });
+//     // 2. ListParts 签名
+//     signMap.ListParts = cos.getAuth({
+//         Method: 'GET',
+//         Key: key,
+//         Expires: expires,
+//         Headers: { host: host },
+//     });
+//     // 3. InitiateMultipartUpload 签名
+//     signMap.InitiateMultipartUpload = cos.getAuth({
+//         Method: 'POST',
+//         Key: key,
+//         Expires: expires,
+//         Query: { uploads: '' },
+//         Headers: { host: host },
+//     });
+//     // 4. UploadPart 签名
+//     signMap.UploadPart = cos.getAuth({
+//         Method: 'PUT',
+//         Key: key,
+//         Expires: expires,
+//         Headers: { host: host, 'x-cos-mime-limit': mimeLimit },
+//     });
+//     // 5. CompleteMultipartUpload 签名
+//     signMap.CompleteMultipartUpload = cos.getAuth({
+//         Method: 'POST',
+//         Key: key,
+//         Expires: expires,
+//         Headers: { host: host },
+//     });
+//     // 6. PutObject 签名
+//     signMap.PutObject = cos.getAuth({
+//         Method: 'PUT',
+//         Key: key,
+//         Expires: expires,
+//         Headers: { host: host, 'x-cos-mime-limit': mimeLimit },
+//     });
+//     res.send({
+//         code: 0,
+//         host,
+//         signMap,
+//         bucket: config.bucket,
+//         region: config.region,
+//         key,
+//         mimeLimit,
+//     });
+// });
+
+app.all('*', function (req, res, next) {
+  res.send({ code: -1, message: '404 Not Found' });
+});
+
+// 启动签名服务
+app.listen(3000);
+console.log('app is listening at http://127.0.0.1:3000');

+ 41 - 0
node_modules/cos-js-sdk-v5/server/sts.php

@@ -0,0 +1,41 @@
+<?php
+// 临时密钥计算样例
+
+include './qcloud-sts-sdk.php'; // 这里获取 sts.php https://github.com/tencentyun/qcloud-cos-sts-sdk/blob/master/php/sts/sts.php
+$sts = new STS();
+
+// 配置参数
+$config = array(
+    'url' => 'https://sts.tencentcloudapi.com/',
+    'domain' => 'sts.tencentcloudapi.com',
+    'proxy' => '',
+    'secretId' => getenv('SecretId'), // 传入密钥 SecretId https://console.cloud.tencent.com/cam/capi
+    'secretKey' => getenv('SecretKey'), // 传入密钥 SecretKey
+    'bucket' => 'test-1250000000', // 换成你的 bucket
+    'region' => 'ap-guangzhou', // 换成 bucket 所在园区
+    'durationSeconds' => 1800, // 密钥有效期
+    // 允许操作(上传)的对象前缀,可以根据自己网站的用户登录态判断允许上传的目录,例子: user1/* 或者 * 或者a.jpg
+    // 请注意当使用 * 时,可能存在安全风险,详情请参阅:https://cloud.tencent.com/document/product/436/40265
+    'allowPrefix' => '_ALLOW_DIR_/*',
+    // 密钥的权限列表。简单上传和分片需要以下的权限,其他权限列表请看 https://cloud.tencent.com/document/product/436/31923
+    'allowActions' => array (
+        // 所有 action 请看文档 https://cloud.tencent.com/document/product/436/31923
+        // 简单上传
+        'name/cos:PutObject',
+        'name/cos:PostObject',
+        // 分片上传
+        'name/cos:InitiateMultipartUpload',
+        'name/cos:ListMultipartUploads',
+        'name/cos:ListParts',
+        'name/cos:UploadPart',
+        'name/cos:CompleteMultipartUpload'
+    )
+);
+// 获取临时密钥,计算签名
+$tempKeys = $sts->getTempKeys($config);
+
+// 返回数据给前端
+header('Content-Type: application/json');
+header('Access-Control-Allow-Origin: http://127.0.0.1'); // 这里修改允许跨域访问的网站
+header('Access-Control-Allow-Headers: origin,accept,content-type');
+echo json_encode($tempKeys);

File diff suppressed because it is too large
+ 1455 - 0
node_modules/cos-js-sdk-v5/src/advance.js


+ 59 - 0
node_modules/cos-js-sdk-v5/src/async.js

@@ -0,0 +1,59 @@
+var eachLimit = function (arr, limit, iterator, callback) {
+  callback = callback || function () {};
+  if (!arr.length || limit <= 0) {
+    return callback();
+  }
+
+  var completed = 0;
+  var started = 0;
+  var running = 0;
+
+  (function replenish() {
+    if (completed >= arr.length) {
+      return callback();
+    }
+
+    while (running < limit && started < arr.length) {
+      started += 1;
+      running += 1;
+      iterator(arr[started - 1], function (err) {
+        if (err) {
+          callback(err);
+          callback = function () {};
+        } else {
+          completed += 1;
+          running -= 1;
+          if (completed >= arr.length) {
+            callback();
+          } else {
+            replenish();
+          }
+        }
+      });
+    }
+  })();
+};
+
+var retry = function (times, iterator, callback) {
+  var next = function (index) {
+    iterator(function (err, data) {
+      if (err && index < times) {
+        next(index + 1);
+      } else {
+        callback(err, data);
+      }
+    });
+  };
+  if (times < 1) {
+    callback();
+  } else {
+    next(1);
+  }
+};
+
+var async = {
+  eachLimit: eachLimit,
+  retry: retry,
+};
+
+module.exports = async;

File diff suppressed because it is too large
+ 4216 - 0
node_modules/cos-js-sdk-v5/src/base.js


+ 95 - 0
node_modules/cos-js-sdk-v5/src/cos.js

@@ -0,0 +1,95 @@
+'use strict';
+
+var util = require('./util');
+var event = require('./event');
+var task = require('./task');
+var base = require('./base');
+var advance = require('./advance');
+var pkg = require('../package.json');
+
+var defaultOptions = {
+  AppId: '', // AppId 已废弃,请拼接到 Bucket 后传入,例如:test-1250000000
+  SecretId: '',
+  SecretKey: '',
+  SecurityToken: '', // 使用临时密钥需要注意自行刷新 Token
+  ChunkRetryTimes: 2,
+  FileParallelLimit: 3,
+  ChunkParallelLimit: 3,
+  ChunkSize: 1024 * 1024,
+  SliceSize: 1024 * 1024,
+  CopyChunkParallelLimit: 20,
+  CopyChunkSize: 1024 * 1024 * 10,
+  CopySliceSize: 1024 * 1024 * 10,
+  MaxPartNumber: 10000,
+  ProgressInterval: 1000,
+  Domain: '',
+  ServiceDomain: '',
+  Protocol: '',
+  CompatibilityMode: false,
+  ForcePathStyle: false,
+  UseRawKey: false,
+  Timeout: 0, // 单位毫秒,0 代表不设置超时时间
+  CorrectClockSkew: true,
+  SystemClockOffset: 0, // 单位毫秒,ms
+  UploadCheckContentMd5: false,
+  UploadQueueSize: 10000,
+  UploadAddMetaMd5: false,
+  UploadIdCacheLimit: 50,
+  UseAccelerate: false,
+  ForceSignHost: true, // 默认将host加入签名计算,关闭后可能导致越权风险,建议保持为true
+  EnableTracker: false, // 默认关闭上报
+  DeepTracker: false, // 上报时是否对每个分块上传做单独上报
+  TrackerDelay: 5000, // 周期性上报,单位毫秒。0代表实时上报
+  CustomId: '', // 自定义上报id
+};
+
+// 对外暴露的类
+var COS = function (options) {
+  this.options = util.extend(util.clone(defaultOptions), options || {});
+  this.options.FileParallelLimit = Math.max(1, this.options.FileParallelLimit);
+  this.options.ChunkParallelLimit = Math.max(1, this.options.ChunkParallelLimit);
+  this.options.ChunkRetryTimes = Math.max(0, this.options.ChunkRetryTimes);
+  this.options.ChunkSize = Math.max(1024 * 1024, this.options.ChunkSize);
+  this.options.CopyChunkParallelLimit = Math.max(1, this.options.CopyChunkParallelLimit);
+  this.options.CopyChunkSize = Math.max(1024 * 1024, this.options.CopyChunkSize);
+  this.options.CopySliceSize = Math.max(0, this.options.CopySliceSize);
+  this.options.MaxPartNumber = Math.max(1024, Math.min(10000, this.options.MaxPartNumber));
+  this.options.Timeout = Math.max(0, this.options.Timeout);
+  if (this.options.AppId) {
+    console.warn(
+      'warning: AppId has been deprecated, Please put it at the end of parameter Bucket(E.g: "test-1250000000").'
+    );
+  }
+  if (this.options.SecretId && this.options.SecretId.indexOf(' ') > -1) {
+    console.error('error: SecretId格式错误,请检查');
+    console.error('error: SecretId format is incorrect. Please check');
+  }
+  if (this.options.SecretKey && this.options.SecretKey.indexOf(' ') > -1) {
+    console.error('error: SecretKey格式错误,请检查');
+    console.error('error: SecretKey format is incorrect. Please check');
+  }
+  if (util.isNode()) {
+    console.warn(
+      'warning: cos-js-sdk-v5 不支持 nodejs 环境使用,请改用 cos-nodejs-sdk-v5,参考文档: https://cloud.tencent.com/document/product/436/8629'
+    );
+    console.warn(
+      'warning: cos-js-sdk-v5 does not support nodejs environment. Please use cos-nodejs-sdk-v5 instead. See: https://cloud.tencent.com/document/product/436/8629'
+    );
+  }
+  event.init(this);
+  task.init(this);
+};
+
+base.init(COS, task);
+advance.init(COS, task);
+
+COS.util = {
+  md5: util.md5,
+  xml2json: util.xml2json,
+  json2xml: util.json2xml,
+  encodeBase64: util.encodeBase64,
+};
+COS.getAuthorization = util.getAuth;
+COS.version = pkg.version;
+
+module.exports = COS;

+ 34 - 0
node_modules/cos-js-sdk-v5/src/event.js

@@ -0,0 +1,34 @@
+var initEvent = function (cos) {
+  var listeners = {};
+  var getList = function (action) {
+    !listeners[action] && (listeners[action] = []);
+    return listeners[action];
+  };
+  cos.on = function (action, callback) {
+    if (action === 'task-list-update') {
+      console.warn('warning: Event "' + action + '" has been deprecated. Please use "list-update" instead.');
+    }
+    getList(action).push(callback);
+  };
+  cos.off = function (action, callback) {
+    var list = getList(action);
+    for (var i = list.length - 1; i >= 0; i--) {
+      callback === list[i] && list.splice(i, 1);
+    }
+  };
+  cos.emit = function (action, data) {
+    var list = getList(action).map(function (cb) {
+      return cb;
+    });
+    for (var i = 0; i < list.length; i++) {
+      list[i](data);
+    }
+  };
+};
+
+var EventProxy = function () {
+  initEvent(this);
+};
+
+module.exports.init = initEvent;
+module.exports.EventProxy = EventProxy;

+ 0 - 0
node_modules/cos-js-sdk-v5/src/session.js


Some files were not shown because too many files changed in this diff