Repository: algorand/js-algorand-sdk
Pull request #609 (2022-07-15 21:18:42)

AVM:  Consolidate TEAL and AVM versions
Applies feedback from https://github.com/algorand/go-algorand/issues/4125 to consolidate TEAL and AVM versions.

michaeldiamant: Related PRs:
* https://github.com/algorand/go-algorand-sdk/pull/345
* https://github.com/algorand/java-algorand-sdk/pull/348
* https://github.com/algorand/js-algorand-sdk/pull/609
* https://github.com/algorand/py-algorand-sdk/pull/361
jdtzmn: These changes look good! I opened [a PR](https://github.com/algorand/js-algorand-sdk/pull/611) for a few test names I saw while reviewing.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 627093a..e0b1167 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,21 @@
+# v1.19.0
+
+## What's Changed
+
+### Bugfixes
+
+- tech-debt: Remove unused/unmaintained templates by @Eric-Warehime in https://github.com/algorand/js-algorand-sdk/pull/607
+
+### New Features
+
+- Dev Tools: Source map decoder by @barnjamin in https://github.com/algorand/js-algorand-sdk/pull/590
+- Enhancement: Upgrade typedoc and plugins by @fionnachan in https://github.com/algorand/js-algorand-sdk/pull/605
+
+### Enhancements
+
+- Github-Actions: Adding PR title and label checks by @algojack in https://github.com/algorand/js-algorand-sdk/pull/600
+- docs: tealSign by @AlgoDoggo in https://github.com/algorand/js-algorand-sdk/pull/610
+
 # v1.18.1
 
 ## What's Changed
diff --git a/README.md b/README.md
index 8082304..d28deac 100644
--- a/README.md
+++ b/README.md
@@ -22,8 +22,8 @@ Include a minified browser bundle directly in your HTML like so:
 
 ```html
 <script
-  src="https://unpkg.com/algosdk@v1.18.1/dist/browser/algosdk.min.js"
-  integrity="sha384-XUkDNLM09jpiPklD96D68Y77m6KhnWov0ZKy8xtca/UO8HIQ0f9OzI05Jxkt+ozd"
+  src="https://unpkg.com/algosdk@v1.19.0/dist/browser/algosdk.min.js"
+  integrity="sha384-5cebCuqDx6A5Y1HeScIKIcSdqsub2M3wwkqTZyu45M8zN/+do8cgxcHDJjkaVTNb"
   crossorigin="anonymous"
 ></script>
 ```
@@ -32,8 +32,8 @@ or
 
 ```html
 <script
-  src="https://cdn.jsdelivr.net/npm/algosdk@v1.18.1/dist/browser/algosdk.min.js"
-  integrity="sha384-XUkDNLM09jpiPklD96D68Y77m6KhnWov0ZKy8xtca/UO8HIQ0f9OzI05Jxkt+ozd"
+  src="https://cdn.jsdelivr.net/npm/algosdk@v1.19.0/dist/browser/algosdk.min.js"
+  integrity="sha384-5cebCuqDx6A5Y1HeScIKIcSdqsub2M3wwkqTZyu45M8zN/+do8cgxcHDJjkaVTNb"
   crossorigin="anonymous"
 ></script>
 ```
diff --git a/package-lock.json b/package-lock.json
index 81e6147..9773bb7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "algosdk",
-  "version": "1.18.1",
+  "version": "1.19.0",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "algosdk",
-      "version": "1.18.1",
+      "version": "1.19.0",
       "license": "MIT",
       "dependencies": {
         "algo-msgpack-with-bigint": "^2.1.1",
@@ -48,12 +48,12 @@
         "prettier": "2.2.1",
         "selenium-webdriver": "^4.2.0",
         "source-map-loader": "^2.0.2",
-        "ts-loader": "^8.3.0",
-        "ts-node": "^10.0.0",
-        "typedoc": "^0.22.13",
-        "typedoc-plugin-missing-exports": "^0.22.6",
-        "typedoc-plugin-rename-defaults": "^0.4.0",
-        "typescript": "^4.2.3",
+        "ts-loader": "^9.3.1",
+        "ts-node": "^10.9.1",
+        "typedoc": "^0.23.8",
+        "typedoc-plugin-missing-exports": "^0.23.0",
+        "typedoc-plugin-rename-defaults": "^0.6.4",
+        "typescript": "^4.7.4",
         "webpack": "^5.38.1",
         "webpack-cli": "^4.7.2"
       },
@@ -166,6 +166,18 @@
         "regenerator-runtime": "^0.13.4"
       }
     },
+    "node_modules/@cspotcode/source-map-support": {
+      "version": "0.8.1",
+      "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+      "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/trace-mapping": "0.3.9"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/@discoveryjs/json-ext": {
       "version": "0.5.3",
       "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz",
@@ -195,6 +207,31 @@
         "node": "^10.12.0 || >=12.0.0"
       }
     },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+      "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.4.14",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+      "dev": true
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.9",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+      "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/resolve-uri": "^3.0.3",
+        "@jridgewell/sourcemap-codec": "^1.4.10"
+      }
+    },
     "node_modules/@microsoft/tsdoc": {
       "version": "0.13.2",
       "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.13.2.tgz",
@@ -310,9 +347,9 @@
       "dev": true
     },
     "node_modules/@tsconfig/node16": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.1.tgz",
-      "integrity": "sha512-FTgBI767POY/lKNDNbIzgAX6miIDBs6NTCbdlDb8TrWovHsSvaVIZDlTqym29C6UqhzwcJx4CYr+AlrMywA0cA==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
+      "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
       "dev": true
     },
     "node_modules/@types/cacheable-request": {
@@ -848,6 +885,15 @@
         "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
       }
     },
+    "node_modules/acorn-walk": {
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+      "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
     "node_modules/adm-zip": {
       "version": "0.5.9",
       "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.9.tgz",
@@ -1206,15 +1252,6 @@
       "integrity": "sha1-Qpzuu/pffpNueNc/vcfacWKyDiA=",
       "dev": true
     },
-    "node_modules/big.js": {
-      "version": "5.2.2",
-      "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
-      "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
-      "dev": true,
-      "engines": {
-        "node": "*"
-      }
-    },
     "node_modules/bignumber.js": {
       "version": "9.0.1",
       "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz",
@@ -2218,15 +2255,6 @@
       "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
       "dev": true
     },
-    "node_modules/emojis-list": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
-      "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
-      "dev": true,
-      "engines": {
-        "node": ">= 4"
-      }
-    },
     "node_modules/encodeurl": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
@@ -2246,17 +2274,16 @@
       }
     },
     "node_modules/enhanced-resolve": {
-      "version": "4.5.0",
-      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz",
-      "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==",
+      "version": "5.10.0",
+      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz",
+      "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==",
       "dev": true,
       "dependencies": {
-        "graceful-fs": "^4.1.2",
-        "memory-fs": "^0.5.0",
-        "tapable": "^1.0.0"
+        "graceful-fs": "^4.2.4",
+        "tapable": "^2.2.0"
       },
       "engines": {
-        "node": ">=6.9.0"
+        "node": ">=10.13.0"
       }
     },
     "node_modules/enquirer": {
@@ -2283,18 +2310,6 @@
         "node": ">=4"
       }
     },
-    "node_modules/errno": {
-      "version": "0.1.8",
-      "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
-      "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
-      "dev": true,
-      "dependencies": {
-        "prr": "~1.0.1"
-      },
-      "bin": {
-        "errno": "cli.js"
-      }
-    },
     "node_modules/error-ex": {
       "version": "1.3.2",
       "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
@@ -4561,21 +4576,6 @@
       "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
       "dev": true
     },
-    "node_modules/json5": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
-      "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
-      "dev": true,
-      "dependencies": {
-        "minimist": "^1.2.5"
-      },
-      "bin": {
-        "json5": "lib/cli.js"
-      },
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/jsonc-parser": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz",
@@ -4778,20 +4778,6 @@
         "node": ">=6.11.5"
       }
     },
-    "node_modules/loader-utils": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
-      "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
-      "dev": true,
-      "dependencies": {
-        "big.js": "^5.2.2",
-        "emojis-list": "^3.0.0",
-        "json5": "^2.1.2"
-      },
-      "engines": {
-        "node": ">=8.9.0"
-      }
-    },
     "node_modules/locate-path": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
@@ -4956,9 +4942,9 @@
       "dev": true
     },
     "node_modules/marked": {
-      "version": "4.0.12",
-      "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.12.tgz",
-      "integrity": "sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ==",
+      "version": "4.0.17",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.17.tgz",
+      "integrity": "sha512-Wfk0ATOK5iPxM4ptrORkFemqroz0ZDxp5MWfYA7H/F+wO17NRWV5Ypxi6p3g2Xmw2bKeiYOl6oVnLHKxBA0VhA==",
       "dev": true,
       "bin": {
         "marked": "bin/marked.js"
@@ -4976,19 +4962,6 @@
         "node": ">= 0.6"
       }
     },
-    "node_modules/memory-fs": {
-      "version": "0.5.0",
-      "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
-      "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==",
-      "dev": true,
-      "dependencies": {
-        "errno": "^0.1.3",
-        "readable-stream": "^2.0.1"
-      },
-      "engines": {
-        "node": ">=4.3.0 <5.0.0 || >=5.10"
-      }
-    },
     "node_modules/merge-descriptors": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
@@ -5970,12 +5943,6 @@
       "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
       "dev": true
     },
-    "node_modules/prr": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
-      "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
-      "dev": true
-    },
     "node_modules/psl": {
       "version": "1.8.0",
       "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
@@ -7154,9 +7121,9 @@
       }
     },
     "node_modules/tapable": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
-      "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
+      "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
       "dev": true,
       "engines": {
         "node": ">=6"
@@ -7362,55 +7329,55 @@
       }
     },
     "node_modules/ts-loader": {
-      "version": "8.3.0",
-      "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.3.0.tgz",
-      "integrity": "sha512-MgGly4I6cStsJy27ViE32UoqxPTN9Xly4anxxVyaIWR+9BGxboV4EyJBGfR3RePV7Ksjj3rHmPZJeIt+7o4Vag==",
+      "version": "9.3.1",
+      "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.3.1.tgz",
+      "integrity": "sha512-OkyShkcZTsTwyS3Kt7a4rsT/t2qvEVQuKCTg4LJmpj9fhFR7ukGdZwV6Qq3tRUkqcXtfGpPR7+hFKHCG/0d3Lw==",
       "dev": true,
       "dependencies": {
         "chalk": "^4.1.0",
-        "enhanced-resolve": "^4.0.0",
-        "loader-utils": "^2.0.0",
+        "enhanced-resolve": "^5.0.0",
         "micromatch": "^4.0.0",
         "semver": "^7.3.4"
       },
       "engines": {
-        "node": ">=10.0.0"
+        "node": ">=12.0.0"
       },
       "peerDependencies": {
         "typescript": "*",
-        "webpack": "*"
+        "webpack": "^5.0.0"
       }
     },
     "node_modules/ts-node": {
-      "version": "10.0.0",
-      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.0.0.tgz",
-      "integrity": "sha512-ROWeOIUvfFbPZkoDis0L/55Fk+6gFQNZwwKPLinacRl6tsxstTF1DbAcLKkovwnpKMVvOMHP1TIbnwXwtLg1gg==",
+      "version": "10.9.1",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
+      "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
       "dev": true,
       "dependencies": {
+        "@cspotcode/source-map-support": "^0.8.0",
         "@tsconfig/node10": "^1.0.7",
         "@tsconfig/node12": "^1.0.7",
         "@tsconfig/node14": "^1.0.0",
-        "@tsconfig/node16": "^1.0.1",
+        "@tsconfig/node16": "^1.0.2",
+        "acorn": "^8.4.1",
+        "acorn-walk": "^8.1.1",
         "arg": "^4.1.0",
         "create-require": "^1.1.0",
         "diff": "^4.0.1",
         "make-error": "^1.1.1",
-        "source-map-support": "^0.5.17",
+        "v8-compile-cache-lib": "^3.0.1",
         "yn": "3.1.1"
       },
       "bin": {
         "ts-node": "dist/bin.js",
         "ts-node-cwd": "dist/bin-cwd.js",
+        "ts-node-esm": "dist/bin-esm.js",
         "ts-node-script": "dist/bin-script.js",
         "ts-node-transpile-only": "dist/bin-transpile.js",
         "ts-script": "dist/bin-script-deprecated.js"
       },
-      "engines": {
-        "node": ">=12.0.0"
-      },
       "peerDependencies": {
-        "@swc/core": ">=1.2.45",
-        "@swc/wasm": ">=1.2.45",
+        "@swc/core": ">=1.2.50",
+        "@swc/wasm": ">=1.2.50",
         "@types/node": "*",
         "typescript": ">=2.7"
       },
@@ -7423,6 +7390,18 @@
         }
       }
     },
+    "node_modules/ts-node/node_modules/acorn": {
+      "version": "8.7.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz",
+      "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==",
+      "dev": true,
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
     "node_modules/ts-node/node_modules/diff": {
       "version": "4.0.2",
       "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
@@ -7538,81 +7517,57 @@
       }
     },
     "node_modules/typedoc": {
-      "version": "0.22.13",
-      "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.13.tgz",
-      "integrity": "sha512-NHNI7Dr6JHa/I3+c62gdRNXBIyX7P33O9TafGLd07ur3MqzcKgwTvpg18EtvCLHJyfeSthAtCLpM7WkStUmDuQ==",
+      "version": "0.23.8",
+      "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.8.tgz",
+      "integrity": "sha512-NLRTY/7XSrhiowR3xnH/nlfTnHk+dkzhHWAMT8guoZ6RHCQZIu3pJREMCqzdkWVCC5+dr9We7TtNeprR3Qy6Ag==",
       "dev": true,
       "dependencies": {
-        "glob": "^7.2.0",
         "lunr": "^2.3.9",
-        "marked": "^4.0.12",
-        "minimatch": "^5.0.1",
+        "marked": "^4.0.16",
+        "minimatch": "^5.1.0",
         "shiki": "^0.10.1"
       },
       "bin": {
         "typedoc": "bin/typedoc"
       },
       "engines": {
-        "node": ">= 12.10.0"
+        "node": ">= 14.14"
       },
       "peerDependencies": {
-        "typescript": "4.0.x || 4.1.x || 4.2.x || 4.3.x || 4.4.x || 4.5.x || 4.6.x"
+        "typescript": "4.6.x || 4.7.x"
       }
     },
     "node_modules/typedoc-plugin-missing-exports": {
-      "version": "0.22.6",
-      "resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-0.22.6.tgz",
-      "integrity": "sha512-1uguGQqa+c5f33nWS3v1mm0uAx4Ii1lw4Kx2zQksmYFKNEWTmrmMXbMNBoBg4wu0p4dFCNC7JIWPoRzpNS6pFA==",
+      "version": "0.23.0",
+      "resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-0.23.0.tgz",
+      "integrity": "sha512-9smahDSsFRno9ZwoEshQDuIYMHWGB1E6LUud5qMxR2wNZ0T4DlZz0QjoK3HzXtX34mUpTH0dYtt7NQUK4D6B6Q==",
       "dev": true,
       "peerDependencies": {
-        "typedoc": "0.22.x"
+        "typedoc": "0.22.x || 0.23.x"
       }
     },
     "node_modules/typedoc-plugin-rename-defaults": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/typedoc-plugin-rename-defaults/-/typedoc-plugin-rename-defaults-0.4.0.tgz",
-      "integrity": "sha512-7m7MbNZKcxCA4Z+0MW06sFEmuQ+he1xfc+rLRtvvQcQypPTd3fgFmkEJKVu42t8mONC+kKS/WkbmqwzsiqI1YQ==",
+      "version": "0.6.4",
+      "resolved": "https://registry.npmjs.org/typedoc-plugin-rename-defaults/-/typedoc-plugin-rename-defaults-0.6.4.tgz",
+      "integrity": "sha512-0rAeNttAfu6ixbi1yu6d+DqNZN8SfRivj2QbnZ4zVa+5HcCPcmQrlR6WHjNzdDfpkGytiiqPTtRD6pAfW/yACg==",
       "dev": true,
       "peerDependencies": {
-        "typedoc": "0.22.x"
-      }
-    },
-    "node_modules/typedoc/node_modules/glob": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
-      "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
-      "dev": true,
-      "dependencies": {
-        "fs.realpath": "^1.0.0",
-        "inflight": "^1.0.4",
-        "inherits": "2",
-        "minimatch": "^3.0.4",
-        "once": "^1.3.0",
-        "path-is-absolute": "^1.0.0"
-      },
-      "engines": {
-        "node": "*"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/isaacs"
+        "typedoc": "0.22.x || 0.23.x"
       }
     },
-    "node_modules/typedoc/node_modules/glob/node_modules/minimatch": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
-      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+    "node_modules/typedoc/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
       "dev": true,
       "dependencies": {
-        "brace-expansion": "^1.1.7"
-      },
-      "engines": {
-        "node": "*"
+        "balanced-match": "^1.0.0"
       }
     },
     "node_modules/typedoc/node_modules/minimatch": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
-      "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz",
+      "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==",
       "dev": true,
       "dependencies": {
         "brace-expansion": "^2.0.1"
@@ -7621,19 +7576,10 @@
         "node": ">=10"
       }
     },
-    "node_modules/typedoc/node_modules/minimatch/node_modules/brace-expansion": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
-      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
-      "dev": true,
-      "dependencies": {
-        "balanced-match": "^1.0.0"
-      }
-    },
     "node_modules/typescript": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz",
-      "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==",
+      "version": "4.7.4",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
+      "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
       "dev": true,
       "bin": {
         "tsc": "bin/tsc",
@@ -7750,6 +7696,12 @@
       "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
       "dev": true
     },
+    "node_modules/v8-compile-cache-lib": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+      "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
+      "dev": true
+    },
     "node_modules/validate-npm-package-license": {
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
@@ -8092,28 +8044,6 @@
         "node": ">=0.4.0"
       }
     },
-    "node_modules/webpack/node_modules/enhanced-resolve": {
-      "version": "5.8.2",
-      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz",
-      "integrity": "sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==",
-      "dev": true,
-      "dependencies": {
-        "graceful-fs": "^4.2.4",
-        "tapable": "^2.2.0"
-      },
-      "engines": {
-        "node": ">=10.13.0"
-      }
-    },
-    "node_modules/webpack/node_modules/tapable": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz",
-      "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==",
-      "dev": true,
-      "engines": {
-        "node": ">=6"
-      }
-    },
     "node_modules/which": {
       "version": "1.3.1",
       "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
@@ -8457,6 +8387,15 @@
         "regenerator-runtime": "^0.13.4"
       }
     },
+    "@cspotcode/source-map-support": {
+      "version": "0.8.1",
+      "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
+      "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
+      "dev": true,
+      "requires": {
+        "@jridgewell/trace-mapping": "0.3.9"
+      }
+    },
     "@discoveryjs/json-ext": {
       "version": "0.5.3",
       "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz",
@@ -8480,6 +8419,28 @@
         "strip-json-comments": "^3.1.1"
       }
     },
+    "@jridgewell/resolve-uri": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+      "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+      "dev": true
+    },
+    "@jridgewell/sourcemap-codec": {
+      "version": "1.4.14",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+      "dev": true
+    },
+    "@jridgewell/trace-mapping": {
+      "version": "0.3.9",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
+      "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
+      "dev": true,
+      "requires": {
+        "@jridgewell/resolve-uri": "^3.0.3",
+        "@jridgewell/sourcemap-codec": "^1.4.10"
+      }
+    },
     "@microsoft/tsdoc": {
       "version": "0.13.2",
       "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.13.2.tgz",
@@ -8576,9 +8537,9 @@
       "dev": true
     },
     "@tsconfig/node16": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.1.tgz",
-      "integrity": "sha512-FTgBI767POY/lKNDNbIzgAX6miIDBs6NTCbdlDb8TrWovHsSvaVIZDlTqym29C6UqhzwcJx4CYr+AlrMywA0cA==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz",
+      "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==",
       "dev": true
     },
     "@types/cacheable-request": {
@@ -9016,6 +8977,12 @@
       "dev": true,
       "requires": {}
     },
+    "acorn-walk": {
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+      "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+      "dev": true
+    },
     "adm-zip": {
       "version": "0.5.9",
       "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.9.tgz",
@@ -9288,12 +9255,6 @@
       "integrity": "sha1-Qpzuu/pffpNueNc/vcfacWKyDiA=",
       "dev": true
     },
-    "big.js": {
-      "version": "5.2.2",
-      "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
-      "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
-      "dev": true
-    },
     "bignumber.js": {
       "version": "9.0.1",
       "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz",
@@ -10074,12 +10035,6 @@
       "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
       "dev": true
     },
-    "emojis-list": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
-      "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
-      "dev": true
-    },
     "encodeurl": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
@@ -10096,14 +10051,13 @@
       }
     },
     "enhanced-resolve": {
-      "version": "4.5.0",
-      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz",
-      "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==",
+      "version": "5.10.0",
+      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz",
+      "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==",
       "dev": true,
       "requires": {
-        "graceful-fs": "^4.1.2",
-        "memory-fs": "^0.5.0",
-        "tapable": "^1.0.0"
+        "graceful-fs": "^4.2.4",
+        "tapable": "^2.2.0"
       }
     },
     "enquirer": {
@@ -10121,15 +10075,6 @@
       "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==",
       "dev": true
     },
-    "errno": {
-      "version": "0.1.8",
-      "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
-      "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
-      "dev": true,
-      "requires": {
-        "prr": "~1.0.1"
-      }
-    },
     "error-ex": {
       "version": "1.3.2",
       "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
@@ -11841,15 +11786,6 @@
       "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
       "dev": true
     },
-    "json5": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz",
-      "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==",
-      "dev": true,
-      "requires": {
-        "minimist": "^1.2.5"
-      }
-    },
     "jsonc-parser": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz",
@@ -12017,17 +11953,6 @@
       "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==",
       "dev": true
     },
-    "loader-utils": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
-      "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
-      "dev": true,
-      "requires": {
-        "big.js": "^5.2.2",
-        "emojis-list": "^3.0.0",
-        "json5": "^2.1.2"
-      }
-    },
     "locate-path": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
@@ -12158,9 +12083,9 @@
       "dev": true
     },
     "marked": {
-      "version": "4.0.12",
-      "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.12.tgz",
-      "integrity": "sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ==",
+      "version": "4.0.17",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.17.tgz",
+      "integrity": "sha512-Wfk0ATOK5iPxM4ptrORkFemqroz0ZDxp5MWfYA7H/F+wO17NRWV5Ypxi6p3g2Xmw2bKeiYOl6oVnLHKxBA0VhA==",
       "dev": true
     },
     "media-typer": {
@@ -12169,16 +12094,6 @@
       "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
       "dev": true
     },
-    "memory-fs": {
-      "version": "0.5.0",
-      "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
-      "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==",
-      "dev": true,
-      "requires": {
-        "errno": "^0.1.3",
-        "readable-stream": "^2.0.1"
-      }
-    },
     "merge-descriptors": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
@@ -12897,12 +12812,6 @@
       "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
       "dev": true
     },
-    "prr": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
-      "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
-      "dev": true
-    },
     "psl": {
       "version": "1.8.0",
       "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
@@ -13820,9 +13729,9 @@
       }
     },
     "tapable": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
-      "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
+      "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
       "dev": true
     },
     "tar": {
@@ -13980,36 +13889,44 @@
       "dev": true
     },
     "ts-loader": {
-      "version": "8.3.0",
-      "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.3.0.tgz",
-      "integrity": "sha512-MgGly4I6cStsJy27ViE32UoqxPTN9Xly4anxxVyaIWR+9BGxboV4EyJBGfR3RePV7Ksjj3rHmPZJeIt+7o4Vag==",
+      "version": "9.3.1",
+      "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.3.1.tgz",
+      "integrity": "sha512-OkyShkcZTsTwyS3Kt7a4rsT/t2qvEVQuKCTg4LJmpj9fhFR7ukGdZwV6Qq3tRUkqcXtfGpPR7+hFKHCG/0d3Lw==",
       "dev": true,
       "requires": {
         "chalk": "^4.1.0",
-        "enhanced-resolve": "^4.0.0",
-        "loader-utils": "^2.0.0",
+        "enhanced-resolve": "^5.0.0",
         "micromatch": "^4.0.0",
         "semver": "^7.3.4"
       }
     },
     "ts-node": {
-      "version": "10.0.0",
-      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.0.0.tgz",
-      "integrity": "sha512-ROWeOIUvfFbPZkoDis0L/55Fk+6gFQNZwwKPLinacRl6tsxstTF1DbAcLKkovwnpKMVvOMHP1TIbnwXwtLg1gg==",
+      "version": "10.9.1",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
+      "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
       "dev": true,
       "requires": {
+        "@cspotcode/source-map-support": "^0.8.0",
         "@tsconfig/node10": "^1.0.7",
         "@tsconfig/node12": "^1.0.7",
         "@tsconfig/node14": "^1.0.0",
-        "@tsconfig/node16": "^1.0.1",
+        "@tsconfig/node16": "^1.0.2",
+        "acorn": "^8.4.1",
+        "acorn-walk": "^8.1.1",
         "arg": "^4.1.0",
         "create-require": "^1.1.0",
         "diff": "^4.0.1",
         "make-error": "^1.1.1",
-        "source-map-support": "^0.5.17",
+        "v8-compile-cache-lib": "^3.0.1",
         "yn": "3.1.1"
       },
       "dependencies": {
+        "acorn": {
+          "version": "8.7.1",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz",
+          "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==",
+          "dev": true
+        },
         "diff": {
           "version": "4.0.2",
           "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
@@ -14102,83 +14019,55 @@
       }
     },
     "typedoc": {
-      "version": "0.22.13",
-      "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.22.13.tgz",
-      "integrity": "sha512-NHNI7Dr6JHa/I3+c62gdRNXBIyX7P33O9TafGLd07ur3MqzcKgwTvpg18EtvCLHJyfeSthAtCLpM7WkStUmDuQ==",
+      "version": "0.23.8",
+      "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.8.tgz",
+      "integrity": "sha512-NLRTY/7XSrhiowR3xnH/nlfTnHk+dkzhHWAMT8guoZ6RHCQZIu3pJREMCqzdkWVCC5+dr9We7TtNeprR3Qy6Ag==",
       "dev": true,
       "requires": {
-        "glob": "^7.2.0",
         "lunr": "^2.3.9",
-        "marked": "^4.0.12",
-        "minimatch": "^5.0.1",
+        "marked": "^4.0.16",
+        "minimatch": "^5.1.0",
         "shiki": "^0.10.1"
       },
       "dependencies": {
-        "glob": {
-          "version": "7.2.0",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
-          "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
+        "brace-expansion": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+          "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
           "dev": true,
           "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          },
-          "dependencies": {
-            "minimatch": {
-              "version": "3.1.2",
-              "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
-              "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
-              "dev": true,
-              "requires": {
-                "brace-expansion": "^1.1.7"
-              }
-            }
+            "balanced-match": "^1.0.0"
           }
         },
         "minimatch": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
-          "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz",
+          "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==",
           "dev": true,
           "requires": {
             "brace-expansion": "^2.0.1"
-          },
-          "dependencies": {
-            "brace-expansion": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
-              "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
-              "dev": true,
-              "requires": {
-                "balanced-match": "^1.0.0"
-              }
-            }
           }
         }
       }
     },
     "typedoc-plugin-missing-exports": {
-      "version": "0.22.6",
-      "resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-0.22.6.tgz",
-      "integrity": "sha512-1uguGQqa+c5f33nWS3v1mm0uAx4Ii1lw4Kx2zQksmYFKNEWTmrmMXbMNBoBg4wu0p4dFCNC7JIWPoRzpNS6pFA==",
+      "version": "0.23.0",
+      "resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-0.23.0.tgz",
+      "integrity": "sha512-9smahDSsFRno9ZwoEshQDuIYMHWGB1E6LUud5qMxR2wNZ0T4DlZz0QjoK3HzXtX34mUpTH0dYtt7NQUK4D6B6Q==",
       "dev": true,
       "requires": {}
     },
     "typedoc-plugin-rename-defaults": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/typedoc-plugin-rename-defaults/-/typedoc-plugin-rename-defaults-0.4.0.tgz",
-      "integrity": "sha512-7m7MbNZKcxCA4Z+0MW06sFEmuQ+he1xfc+rLRtvvQcQypPTd3fgFmkEJKVu42t8mONC+kKS/WkbmqwzsiqI1YQ==",
+      "version": "0.6.4",
+      "resolved": "https://registry.npmjs.org/typedoc-plugin-rename-defaults/-/typedoc-plugin-rename-defaults-0.6.4.tgz",
+      "integrity": "sha512-0rAeNttAfu6ixbi1yu6d+DqNZN8SfRivj2QbnZ4zVa+5HcCPcmQrlR6WHjNzdDfpkGytiiqPTtRD6pAfW/yACg==",
       "dev": true,
       "requires": {}
     },
     "typescript": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz",
-      "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==",
+      "version": "4.7.4",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz",
+      "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==",
       "dev": true
     },
     "uid-safe": {
@@ -14272,6 +14161,12 @@
       "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
       "dev": true
     },
+    "v8-compile-cache-lib": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
+      "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
+      "dev": true
+    },
     "validate-npm-package-license": {
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
@@ -14362,22 +14257,6 @@
           "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.3.0.tgz",
           "integrity": "sha512-tqPKHZ5CaBJw0Xmy0ZZvLs1qTV+BNFSyvn77ASXkpBNfIRk8ev26fKrD9iLGwGA9zedPao52GSHzq8lyZG0NUw==",
           "dev": true
-        },
-        "enhanced-resolve": {
-          "version": "5.8.2",
-          "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz",
-          "integrity": "sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==",
-          "dev": true,
-          "requires": {
-            "graceful-fs": "^4.2.4",
-            "tapable": "^2.2.0"
-          }
-        },
-        "tapable": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz",
-          "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==",
-          "dev": true
         }
       }
     },
diff --git a/package.json b/package.json
index aaff3a5..9648348 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "algosdk",
-  "version": "1.18.1",
+  "version": "1.19.0",
   "description": "The official JavaScript SDK for Algorand",
   "main": "dist/cjs/index.js",
   "module": "dist/esm/index.js",
@@ -59,12 +59,12 @@
     "prettier": "2.2.1",
     "selenium-webdriver": "^4.2.0",
     "source-map-loader": "^2.0.2",
-    "ts-loader": "^8.3.0",
-    "ts-node": "^10.0.0",
-    "typedoc": "^0.22.13",
-    "typedoc-plugin-missing-exports": "^0.22.6",
-    "typedoc-plugin-rename-defaults": "^0.4.0",
-    "typescript": "^4.2.3",
+    "ts-loader": "^9.3.1",
+    "ts-node": "^10.9.1",
+    "typedoc": "^0.23.8",
+    "typedoc-plugin-missing-exports": "^0.23.0",
+    "typedoc-plugin-rename-defaults": "^0.6.4",
+    "typescript": "^4.7.4",
     "webpack": "^5.38.1",
     "webpack-cli": "^4.7.2"
   },
@@ -73,8 +73,8 @@
     "prepare": "npm run build",
     "prepare-browser-tests": "npm run build && mkdir -p tests/cucumber/browser/build && cp dist/browser/algosdk.min.* tests/cucumber/browser/build/ && webpack --config tests/cucumber/browser/webpack.config.js",
     "build": "concurrently \"webpack --config webpack.config.js\" \"tsc -p tsconfig-esm.json\" \"tsc -p tsconfig-cjs.json\"",
-    "docs": "typedoc src/main.ts --options typedoc.config.json",
-    "docs:dev": "typedoc src/main.ts --options typedoc.config.json --watch --preserveWatchOutput",
+    "docs": "typedoc --options typedoc.config.json",
+    "docs:dev": "typedoc --options typedoc.config.json --watch --preserveWatchOutput",
     "lint": "eslint .",
     "lint:fix": "eslint --fix .",
     "format": "prettier --write .",
diff --git a/src/logic/logic.ts b/src/logic/logic.ts
index 9d8d60e..9f66b23 100644
--- a/src/logic/logic.ts
+++ b/src/logic/logic.ts
@@ -247,9 +247,7 @@ export function readProgram(
   }
   // costs calculated dynamically starting in v4
   if (version < 4 && cost > maxCost) {
-    throw new Error(
-      'program too costly for Teal version < 4. consider using v4.'
-    );
+    throw new Error('program too costly for version < 4. consider using v4.');
   }
   return [ints, byteArrays, true];
 }
diff --git a/src/logicsig.ts b/src/logicsig.ts
index 3a42908..4904d3c 100644
--- a/src/logicsig.ts
+++ b/src/logicsig.ts
@@ -456,18 +456,18 @@ export function logicSigFromByte(encoded: Uint8Array) {
 const SIGN_PROGRAM_DATA_PREFIX = Buffer.from('ProgData');
 
 /**
- * tealSign creates a signature compatible with ed25519verify opcode from contract address
+ * tealSign creates a signature compatible with ed25519verify opcode from program hash
  * @param sk - uint8array with secret key
  * @param data - buffer with data to sign
- * @param contractAddress - string representation of teal contract address (program hash)
+ * @param programHash - string representation of teal program hash (= contract address for LogicSigs)
  */
 export function tealSign(
   sk: Uint8Array,
   data: Uint8Array | Buffer,
-  contractAddress: string
+  programHash: string
 ) {
   const parts = utils.concatArrays(
-    address.decodeAddress(contractAddress).publicKey,
+    address.decodeAddress(programHash).publicKey,
     data
   );
   const toBeSigned = Buffer.from(
diff --git a/src/main.ts b/src/main.ts
index 12d8534..9c27efa 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -166,6 +166,9 @@ export {
   signMultisigTransaction,
   mergeMultisigTransactions,
   appendSignMultisigTransaction,
+  createMultisigTransaction,
+  appendSignRawMultisigSignature,
+  verifyMultisig,
   multisigAddress,
 } from './multisig';
 export { SourceMap } from './logic/sourcemap';
diff --git a/src/multisig.ts b/src/multisig.ts
index 5c89fcb..245ac67 100644
--- a/src/multisig.ts
+++ b/src/multisig.ts
@@ -29,6 +29,8 @@ export const MULTISIG_NO_MUTATE_ERROR_MSG =
   'Cannot mutate a multisig field as it would invalidate all existing signatures.';
 export const MULTISIG_USE_PARTIAL_SIGN_ERROR_MSG =
   'Cannot sign a multisig transaction using `signTxn`. Use `partialSignTxn` instead.';
+export const MULTISIG_SIGNATURE_LENGTH_ERROR_MSG =
+  'Cannot add multisig signature. Signature is not of the correct length.';
 
 interface MultisigOptions {
   rawSig: Uint8Array;
@@ -40,41 +42,27 @@ interface MultisigMetadataWithPks extends Omit<MultisigMetadata, 'addrs'> {
 }
 
 /**
- * createMultisigTransaction creates a multisig transaction blob.
- * @param txnForEncoding - the actual transaction to sign.
- * @param rawSig - a Buffer raw signature of that transaction
- * @param myPk - a public key that corresponds with rawSig
+ * createRawMultisigTransaction creates a raw, unsigned multisig transaction blob.
+ * @param txn - the actual transaction.
  * @param version - multisig version
- * @param threshold - mutlisig threshold
+ * @param threshold - multisig threshold
  * @param pks - ordered list of public keys in this multisig
  * @returns encoded multisig blob
  */
-function createMultisigTransaction(
-  txnForEncoding: EncodedTransaction,
-  { rawSig, myPk }: MultisigOptions,
-  { version, threshold, pks }: MultisigMetadataWithPks
+export function createMultisigTransaction(
+  txn: txnBuilder.Transaction,
+  { version, threshold, addrs }: MultisigMetadata
 ) {
-  let keyExist = false;
   // construct the appendable multisigned transaction format
-  const subsigs = pks.map((pk) => {
-    if (nacl.bytesEqual(pk, myPk)) {
-      keyExist = true;
-      return {
-        pk: Buffer.from(pk),
-        s: rawSig,
-      };
-    }
-    return { pk: Buffer.from(pk) };
-  });
-  if (keyExist === false) {
-    throw new Error(MULTISIG_KEY_NOT_EXIST_ERROR_MSG);
-  }
+  const pks = addrs.map((addr) => address.decodeAddress(addr).publicKey);
+  const subsigs = pks.map((pk) => ({ pk: Buffer.from(pk) }));
 
   const msig: EncodedMultisig = {
     v: version,
     thr: threshold,
     subsig: subsigs,
   };
+  const txnForEncoding = txn.get_obj_for_encoding();
   const signedTxn: EncodedSignedTransaction = {
     msig,
     txn: txnForEncoding,
@@ -97,6 +85,58 @@ function createMultisigTransaction(
   return new Uint8Array(encoding.encode(signedTxn));
 }
 
+/**
+ * createMultisigTransactionWithSignature creates a multisig transaction blob with an included signature.
+ * @param txn - the actual transaction to sign.
+ * @param rawSig - a Buffer raw signature of that transaction
+ * @param myPk - a public key that corresponds with rawSig
+ * @param version - multisig version
+ * @param threshold - multisig threshold
+ * @param pks - ordered list of public keys in this multisig
+ * @returns encoded multisig blob
+ */
+function createMultisigTransactionWithSignature(
+  txn: txnBuilder.Transaction,
+  { rawSig, myPk }: MultisigOptions,
+  { version, threshold, pks }: MultisigMetadataWithPks
+) {
+  // Create an empty encoded multisig transaction
+  const encodedMsig = createMultisigTransaction(txn, {
+    version,
+    threshold,
+    addrs: pks.map((pk) => address.encodeAddress(pk)),
+  });
+  // note: this is not signed yet, but will be shortly
+  const signedTxn = encoding.decode(encodedMsig) as EncodedSignedTransaction;
+
+  let keyExist = false;
+  // append the multisig signature to the corresponding public key in the multisig blob
+  signedTxn.msig.subsig.forEach((subsig, i) => {
+    if (nacl.bytesEqual(subsig.pk, myPk)) {
+      keyExist = true;
+      signedTxn.msig.subsig[i].s = rawSig;
+    }
+  });
+  if (keyExist === false) {
+    throw new Error(MULTISIG_KEY_NOT_EXIST_ERROR_MSG);
+  }
+
+  // if the address of this multisig is different from the transaction sender,
+  // we need to add the auth-addr field
+  const msigAddr = address.fromMultisigPreImg({
+    version,
+    threshold,
+    pks,
+  });
+  if (
+    address.encodeAddress(signedTxn.txn.snd) !== address.encodeAddress(msigAddr)
+  ) {
+    signedTxn.sgnr = Buffer.from(msigAddr);
+  }
+
+  return new Uint8Array(encoding.encode(signedTxn));
+}
+
 /**
  * MultisigTransaction is a Transaction that also supports creating partially-signed multisig transactions.
  */
@@ -140,13 +180,39 @@ export class MultisigTransaction extends txnBuilder.Transaction {
   ) {
     // get signature verifier
     const myPk = nacl.keyPairFromSecretKey(sk).publicKey;
-    return createMultisigTransaction(
-      this.get_obj_for_encoding(),
+    return createMultisigTransactionWithSignature(
+      this,
       { rawSig: this.rawSignTxn(sk), myPk },
       { version, threshold, pks }
     );
   }
 
+  /**
+   * partialSignWithMultisigSignature partially signs this transaction with an external raw multisig signature and returns
+   * a partially-signed multisig transaction, encoded with msgpack as a typed array.
+   * @param metadata - multisig metadata
+   * @param signerAddr - address of the signer
+   * @param signature - raw multisig signature
+   * @returns an encoded, partially signed multisig transaction.
+   */
+  partialSignWithMultisigSignature(
+    metadata: MultisigMetadataWithPks,
+    signerAddr: string,
+    signature: Uint8Array
+  ) {
+    if (!nacl.isValidSignatureLength(signature.length)) {
+      throw new Error(MULTISIG_SIGNATURE_LENGTH_ERROR_MSG);
+    }
+    return createMultisigTransactionWithSignature(
+      this,
+      {
+        rawSig: signature,
+        myPk: address.decodeAddress(signerAddr).publicKey,
+      },
+      metadata
+    );
+  }
+
   // eslint-disable-next-line camelcase
   static from_obj_for_encoding(
     txnForEnc: EncodedTransaction
@@ -312,7 +378,7 @@ export function verifyMultisig(
 /**
  * signMultisigTransaction takes a raw transaction (see signTransaction), a multisig preimage, a secret key, and returns
  * a multisig transaction, which is a blob representing a transaction and multisignature account preimage. The returned
- * multisig txn can accumulate additional signatures through mergeMultisigTransactions or appendMultisigTransaction.
+ * multisig txn can accumulate additional signatures through mergeMultisigTransactions or appendSignMultisigTransaction.
  * @param txn - object with either payment or key registration fields
  * @param version - multisig version
  * @param threshold - multisig threshold
@@ -391,9 +457,43 @@ export function appendSignMultisigTransaction(
   };
 }
 
+/**
+ * appendMultisigTransactionSignature takes a multisig transaction blob, and appends a given raw signature to it.
+ * This makes it possible to compile a multisig signature using only raw signatures from external methods.
+ * @param multisigTxnBlob - an encoded multisig txn. Supports non-payment txn types.
+ * @param version - multisig version
+ * @param threshold - multisig threshold
+ * @param addrs - a list of Algorand addresses representing possible signers for this multisig. Order is important.
+ * @param signerAddr - address of the signer
+ * @param signature - raw multisig signature
+ * @returns object containing txID, and blob representing encoded multisig txn
+ */
+export function appendSignRawMultisigSignature(
+  multisigTxnBlob: Uint8Array,
+  { version, threshold, addrs }: MultisigMetadata,
+  signerAddr: string,
+  signature: Uint8Array
+) {
+  const pks = addrs.map((addr) => address.decodeAddress(addr).publicKey);
+  // obtain underlying txn, sign it, and merge it
+  const multisigTxObj = encoding.decode(
+    multisigTxnBlob
+  ) as EncodedSignedTransaction;
+  const msigTxn = MultisigTransaction.from_obj_for_encoding(multisigTxObj.txn);
+  const partialSignedBlob = msigTxn.partialSignWithMultisigSignature(
+    { version, threshold, pks },
+    signerAddr,
+    signature
+  );
+  return {
+    txID: msigTxn.txID().toString(),
+    blob: mergeMultisigTransactions([multisigTxnBlob, partialSignedBlob]),
+  };
+}
+
 /**
  * multisigAddress takes multisig metadata (preimage) and returns the corresponding human readable Algorand address.
- * @param version - mutlisig version
+ * @param version - multisig version
  * @param threshold - multisig threshold
  * @param addrs - list of Algorand addresses
  */
diff --git a/src/nacl/naclWrappers.ts b/src/nacl/naclWrappers.ts
index 754f48f..91027ee 100644
--- a/src/nacl/naclWrappers.ts
+++ b/src/nacl/naclWrappers.ts
@@ -18,6 +18,10 @@ export function keyPair() {
   return keyPairFromSeed(seed);
 }
 
+export function isValidSignatureLength(len: number) {
+  return len === nacl.sign.signatureLength;
+}
+
 export function keyPairFromSecretKey(sk: Uint8Array) {
   return nacl.sign.keyPair.fromSecretKey(sk);
 }
diff --git a/src/transaction.ts b/src/transaction.ts
index 10825a4..4f737a0 100644
--- a/src/transaction.ts
+++ b/src/transaction.ts
@@ -1035,6 +1035,22 @@ export class Transaction implements TransactionStorageStructure {
     return new Uint8Array(encoding.encode(sTxn));
   }
 
+  attachSignature(signerAddr: string, signature: Uint8Array) {
+    if (!nacl.isValidSignatureLength(signature.length)) {
+      throw new Error('Invalid signature length');
+    }
+    const sTxn: EncodedSignedTransaction = {
+      sig: Buffer.from(signature),
+      txn: this.get_obj_for_encoding(),
+    };
+    // add AuthAddr if signing with a different key than From indicates
+    if (signerAddr !== address.encodeAddress(this.from.publicKey)) {
+      const signerPublicKey = address.decodeAddress(signerAddr).publicKey;
+      sTxn.sgnr = Buffer.from(signerPublicKey);
+    }
+    return new Uint8Array(encoding.encode(sTxn));
+  }
+
   rawTxID() {
     const enMsg = this.toByte();
     const gh = Buffer.from(utils.concatArrays(this.tag, enMsg));
diff --git a/typedoc.config.json b/typedoc.config.json
index 4b53fab..ce478d0 100644
--- a/typedoc.config.json
+++ b/typedoc.config.json
@@ -1,3 +1,6 @@
 {
-  "excludeExternals": true
+  "excludeExternals": true,
+  "entryPoints": ["./src/main.ts"],
+  "entryPointStrategy": "expand",
+  "out": "docs"
 }


Test patch:
diff --git a/tests/4.Utils.ts b/tests/4.Utils.ts
index a06abbb..c372fed 100644
--- a/tests/4.Utils.ts
+++ b/tests/4.Utils.ts
@@ -1,5 +1,6 @@
 import assert from 'assert';
 import * as utils from '../src/utils/utils';
+import * as nacl from '../src/nacl/naclWrappers';
 
 describe('utils', () => {
   describe('concatArrays', () => {
@@ -33,3 +34,10 @@ describe('utils', () => {
     });
   });
 });
+
+describe('nacl wrapper', () => {
+  it('should validate signature length', () => {
+    assert.strictEqual(nacl.isValidSignatureLength(6), false);
+    assert.strictEqual(nacl.isValidSignatureLength(64), true);
+  });
+});
diff --git a/tests/6.Multisig.ts b/tests/6.Multisig.ts
index d4b0e24..7dc7596 100644
--- a/tests/6.Multisig.ts
+++ b/tests/6.Multisig.ts
@@ -4,6 +4,7 @@ import {
   MultisigTransaction,
   MULTISIG_NO_MUTATE_ERROR_MSG,
   MULTISIG_USE_PARTIAL_SIGN_ERROR_MSG,
+  MULTISIG_SIGNATURE_LENGTH_ERROR_MSG,
 } from '../src/multisig';
 
 const sampleAccount1 = algosdk.mnemonicToSecretKey(
@@ -167,6 +168,169 @@ describe('Multisig Functionality', () => {
     });
   });
 
+  describe('create/append multisig with external signatures', () => {
+    it('should match golden main repo result', () => {
+      const oneSigTxn = Buffer.from(
+        'gqRtc2lng6ZzdWJzaWeTgqJwa8QgG37AsEvqYbeWkJfmy/QH4QinBTUdC8mKvrEiCairgXihc8RAuLAFE0oma0skOoAmOzEwfPuLYpEWl4LINtsiLrUqWQkDxh4WHb29//YCpj4MFbiSgD2jKYt0XKRD86zKCF4RDYGicGvEIAljMglTc4nwdWcRdzmRx9A+G3PIxPUr9q/wGqJc+cJxgaJwa8Qg5/D4TQaBHfnzHI2HixFV9GcdUaGFwgCQhmf0SVhwaKGjdGhyAqF2AaN0eG6Lo2FtdM0D6KVjbG9zZcQgQOk0koglZMvOnFmmm2dUJonpocOiqepbZabopEIf/FejZmVlzQPoomZ2zfMVo2dlbqxkZXZuZXQtdjM4LjCiZ2jEIP6zbDkQFDkAw9pVQsoYNrAP0vgZWRJXzSP2BC+YyDadomx2zfb9pG5vdGXECEUmIgAYUob7o3JjdsQge2ziT+tbrMCxZOKcIixX9fY9w4fUOQSCWEEcX+EPfAKjc25kxCCNkrSJkAFzoE36Q1mjZmpq/OosQqBd2cH3PuulR4A36aR0eXBlo3BheQ==',
+        'base64'
+      );
+
+      const signerAddr = sampleAccount2.addr;
+      const signedTxn = algosdk.appendSignMultisigTransaction(
+        oneSigTxn,
+        sampleMultisigParams,
+        sampleAccount2.sk
+      );
+
+      const multisig = algosdk.decodeSignedTransaction(signedTxn.blob).msig;
+      if (multisig === undefined) {
+        throw new Error('multisig is undefined');
+      }
+
+      const signatures = multisig.subsig;
+      if (signatures === undefined) {
+        throw new Error('No signatures found');
+      }
+
+      const signature = signatures[1].s;
+      if (signature === undefined) {
+        throw new Error('No signature found');
+      }
+
+      const { txID, blob } = algosdk.appendSignRawMultisigSignature(
+        oneSigTxn,
+        sampleMultisigParams,
+        signerAddr,
+        signature
+      );
+
+      const expectedTxID =
+        'MANN3ESOHQVHFZBAGD6UK6XFVWEFZQJPWO5SQ2J5LZRCF5E2VVQQ';
+      assert.strictEqual(txID, expectedTxID);
+
+      const expectedBlob = Buffer.from(
+        'gqRtc2lng6ZzdWJzaWeTgqJwa8QgG37AsEvqYbeWkJfmy/QH4QinBTUdC8mKvrEiCairgXihc8RAuLAFE0oma0skOoAmOzEwfPuLYpEWl4LINtsiLrUqWQkDxh4WHb29//YCpj4MFbiSgD2jKYt0XKRD86zKCF4RDYKicGvEIAljMglTc4nwdWcRdzmRx9A+G3PIxPUr9q/wGqJc+cJxoXPEQBAhuyRjsOrnHp3s/xI+iMKiL7QPsh8iJZ22YOJJP0aFUwedMr+a6wfdBXk1OefyrAN1wqJ9rq6O+DrWV1fH0ASBonBrxCDn8PhNBoEd+fMcjYeLEVX0Zx1RoYXCAJCGZ/RJWHBooaN0aHICoXYBo3R4boujYW10zQPopWNsb3NlxCBA6TSSiCVky86cWaabZ1Qmiemhw6Kp6ltlpuikQh/8V6NmZWXNA+iiZnbN8xWjZ2VurGRldm5ldC12MzguMKJnaMQg/rNsORAUOQDD2lVCyhg2sA/S+BlZElfNI/YEL5jINp2ibHbN9v2kbm90ZcQIRSYiABhShvujcmN2xCB7bOJP61uswLFk4pwiLFf19j3Dh9Q5BIJYQRxf4Q98AqNzbmTEII2StImQAXOgTfpDWaNmamr86ixCoF3Zwfc+66VHgDfppHR5cGWjcGF5',
+        'base64'
+      );
+
+      assert.deepStrictEqual(Buffer.from(blob), expectedBlob);
+    });
+
+    it('should not sign with signature of invalid length', () => {
+      const oneSigTxn = Buffer.from(
+        'gqRtc2lng6ZzdWJzaWeTgqJwa8QgG37AsEvqYbeWkJfmy/QH4QinBTUdC8mKvrEiCairgXihc8RAuLAFE0oma0skOoAmOzEwfPuLYpEWl4LINtsiLrUqWQkDxh4WHb29//YCpj4MFbiSgD2jKYt0XKRD86zKCF4RDYGicGvEIAljMglTc4nwdWcRdzmRx9A+G3PIxPUr9q/wGqJc+cJxgaJwa8Qg5/D4TQaBHfnzHI2HixFV9GcdUaGFwgCQhmf0SVhwaKGjdGhyAqF2AaN0eG6Lo2FtdM0D6KVjbG9zZcQgQOk0koglZMvOnFmmm2dUJonpocOiqepbZabopEIf/FejZmVlzQPoomZ2zfMVo2dlbqxkZXZuZXQtdjM4LjCiZ2jEIP6zbDkQFDkAw9pVQsoYNrAP0vgZWRJXzSP2BC+YyDadomx2zfb9pG5vdGXECEUmIgAYUob7o3JjdsQge2ziT+tbrMCxZOKcIixX9fY9w4fUOQSCWEEcX+EPfAKjc25kxCCNkrSJkAFzoE36Q1mjZmpq/OosQqBd2cH3PuulR4A36aR0eXBlo3BheQ==',
+        'base64'
+      );
+
+      const signerAddr = sampleAccount2.addr;
+      const signedTxn = algosdk.appendSignMultisigTransaction(
+        oneSigTxn,
+        sampleMultisigParams,
+        sampleAccount2.sk
+      );
+
+      const multisig = algosdk.decodeSignedTransaction(signedTxn.blob).msig;
+      if (multisig === undefined) {
+        throw new Error('multisig is undefined');
+      }
+
+      const signatures = multisig.subsig;
+      if (signatures === undefined) {
+        throw new Error('No signatures found');
+      }
+
+      const signature = signatures[1].s;
+      if (signature === undefined) {
+        throw new Error('No signature found');
+      }
+
+      // Remove the last byte of the signature
+      const invalidSignature = signature.slice(0, -1);
+      assert.throws(
+        () =>
+          algosdk.appendSignRawMultisigSignature(
+            oneSigTxn,
+            sampleMultisigParams,
+            signerAddr,
+            invalidSignature
+          ),
+        Error(MULTISIG_SIGNATURE_LENGTH_ERROR_MSG)
+      );
+    });
+
+    it('should append signature to created raw multisig transaction', () => {
+      const rawTxBlob = Buffer.from(
+        'jKNmZWXOAAPIwKJmds4ADvnao2dlbqxkZXZuZXQtdjM4LjCiZ2jEIP6zbDkQFDkAw9pVQsoYNrAP0vgZWRJXzSP2BC+YyDadomx2zgAO/cKmc2Vsa2V5xCAyEisr1j3cUzGWF6WqU8Sxwm/j3MryjTYitWl3oUBchqNzbmTEII2StImQAXOgTfpDWaNmamr86ixCoF3Zwfc+66VHgDfppHR5cGWma2V5cmVnp3ZvdGVmc3TOAA27oKZ2b3Rla2TNJxCndm90ZWtlecQgcBvX+5ErB7MIEf8oHZ/ulWPlgC4gJokjGSWPd/qTHoindm90ZWxzdM4AD0JA',
+        'base64'
+      );
+      const decRawTx = algosdk.decodeUnsignedTransaction(rawTxBlob);
+
+      const unsignedMultisigTx = algosdk.createMultisigTransaction(
+        decRawTx,
+        sampleMultisigParams
+      );
+
+      // Check that the unsignedMultisigTx is valid
+      interface ExpectedMultisigTxStructure {
+        msig: {
+          subsig: {
+            pk: Uint8Array;
+            s: Uint8Array;
+          }[];
+        };
+      }
+      const unsignedMultisigTxBlob = algosdk.decodeObj(
+        unsignedMultisigTx
+      ) as ExpectedMultisigTxStructure;
+      assert.deepStrictEqual(
+        unsignedMultisigTxBlob.msig.subsig[0].pk,
+        algosdk.decodeAddress(sampleAccount1.addr).publicKey
+      );
+      assert.strictEqual(unsignedMultisigTxBlob.msig.subsig[1].s, undefined);
+
+      // Sign the raw transaction with a signature generated from the first account
+      const signerAddr = sampleAccount1.addr;
+      const signedTxn = algosdk.appendSignMultisigTransaction(
+        unsignedMultisigTx,
+        sampleMultisigParams,
+        sampleAccount1.sk
+      );
+
+      const multisig = algosdk.decodeSignedTransaction(signedTxn.blob).msig;
+      if (multisig === undefined) {
+        throw new Error('multisig is undefined');
+      }
+
+      const signatures = multisig.subsig;
+      if (signatures === undefined) {
+        throw new Error('No signatures found');
+      }
+
+      const signature = signatures[0].s;
+      if (signature === undefined) {
+        throw new Error('No signature found');
+      }
+      const { txID, blob } = algosdk.appendSignRawMultisigSignature(
+        unsignedMultisigTx,
+        sampleMultisigParams,
+        signerAddr,
+        signature
+      );
+
+      // Check that the signed raw multisig is valid
+      const expectedTxID =
+        'E7DA7WTJCWWFQMKSVU5HOIJ5F5HGVGMOZGBIHRJRYGIX7FIJ5VWA';
+      assert.strictEqual(txID, expectedTxID);
+
+      const expectedBlob = Buffer.from(
+        'gqRtc2lng6ZzdWJzaWeTgqJwa8QgG37AsEvqYbeWkJfmy/QH4QinBTUdC8mKvrEiCairgXihc8RAcT0s17wJbvnza+NpyHwM0RWbQ+HwKmsT1PLs+w6d6MpdTH3tra+yKZE0K0qEyhSE7Y56+B9oaf2orEbjc/njDYGicGvEIAljMglTc4nwdWcRdzmRx9A+G3PIxPUr9q/wGqJc+cJxgaJwa8Qg5/D4TQaBHfnzHI2HixFV9GcdUaGFwgCQhmf0SVhwaKGjdGhyAqF2AaN0eG6Mo2ZlZc4AA8jAomZ2zgAO+dqjZ2VurGRldm5ldC12MzguMKJnaMQg/rNsORAUOQDD2lVCyhg2sA/S+BlZElfNI/YEL5jINp2ibHbOAA79wqZzZWxrZXnEIDISKyvWPdxTMZYXpapTxLHCb+PcyvKNNiK1aXehQFyGo3NuZMQgjZK0iZABc6BN+kNZo2ZqavzqLEKgXdnB9z7rpUeAN+mkdHlwZaZrZXlyZWendm90ZWZzdM4ADbugpnZvdGVrZM0nEKd2b3Rla2V5xCBwG9f7kSsHswgR/ygdn+6VY+WALiAmiSMZJY93+pMeiKd2b3RlbHN0zgAPQkA=',
+        'base64'
+      );
+
+      assert.deepStrictEqual(Buffer.from(blob), expectedBlob);
+    });
+  });
+
   describe('should sign keyreg transaction types', () => {
     it('first partial sig should match golden main repo result', () => {
       const rawTxBlob = Buffer.from(
diff --git a/tests/7.AlgoSDK.js b/tests/7.AlgoSDK.js
index 6ad333d..e831786 100644
--- a/tests/7.AlgoSDK.js
+++ b/tests/7.AlgoSDK.js
@@ -261,6 +261,7 @@ describe('Algosdk (AKA end to end)', () => {
       const signed = algosdk.signBytes(toSign, account.sk);
       assert.equal(true, algosdk.verifyBytes(toSign, signed, account.addr));
     });
+
     it('should not verify a corrupted signature', () => {
       const account = algosdk.generateAccount();
       const toSign = Buffer.from([1, 9, 25, 49]);
@@ -268,6 +269,71 @@ describe('Algosdk (AKA end to end)', () => {
       signed[0] = (signed[0] + 1) % 256;
       assert.equal(false, algosdk.verifyBytes(toSign, signed, account.addr));
     });
+
+    it('should attach arbitrary signatures', () => {
+      const sender = algosdk.generateAccount();
+      const signer = algosdk.generateAccount();
+
+      // Create a transaction
+      const txn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
+        from: sender.addr,
+        to: signer.addr,
+        amount: 1000,
+        suggestedParams: {
+          firstRound: 12466,
+          lastRound: 13466,
+          genesisID: 'devnet-v33.0',
+          genesisHash: 'JgsgCaCTqIaLeVhyL6XlRu3n7Rfk2FxMeK+wRSaQ7dI=',
+          fee: 4,
+        },
+      });
+
+      // Sign it directly to get a signature
+      const signedWithSk = txn.signTxn(signer.sk);
+      const decoded = algosdk.decodeObj(signedWithSk);
+      const signature = decoded.sig;
+
+      // Attach the signature to the transaction indirectly, and compare
+      const signedWithSignature = txn.attachSignature(signer.addr, signature);
+      assert.deepEqual(signedWithSk, signedWithSignature);
+
+      // Check that signer was set
+      const decodedWithSigner = algosdk.decodeObj(signedWithSignature);
+      assert.deepEqual(
+        decodedWithSigner.sgnr,
+        algosdk.decodeAddress(signer.addr).publicKey
+      );
+    });
+
+    it('should not attach signature with incorrect length', () => {
+      const sender = algosdk.generateAccount();
+      const signer = algosdk.generateAccount();
+
+      // Create a transaction
+      const txn = algosdk.makePaymentTxnWithSuggestedParamsFromObject({
+        from: sender.addr,
+        to: signer.addr,
+        amount: 1000,
+        suggestedParams: {
+          firstRound: 12466,
+          lastRound: 13466,
+          genesisID: 'devnet-v33.0',
+          genesisHash: 'JgsgCaCTqIaLeVhyL6XlRu3n7Rfk2FxMeK+wRSaQ7dI=',
+          fee: 4,
+        },
+      });
+
+      // Sign it directly to get a signature
+      const signedWithSk = txn.signTxn(signer.sk);
+      const decoded = algosdk.decodeObj(signedWithSk);
+      const signature = decoded.sig.slice(0, -1); // without the last byte
+
+      // Check that the signature is not attached
+      assert.throws(
+        () => txn.attachSignature(signer.addr, signature),
+        Error('Invalid signature length')
+      );
+    });
   });
 
   describe('Multisig Sign', () => {
diff --git a/tests/8.LogicSig.ts b/tests/8.LogicSig.ts
index 9947ac3..e7e7a5f 100644
--- a/tests/8.LogicSig.ts
+++ b/tests/8.LogicSig.ts
@@ -872,9 +872,7 @@ describe('Program validation', () => {
         program[0] = oldVersions[i];
         assert.throws(
           () => logic.checkProgram(program),
-          new Error(
-            'program too costly for Teal version < 4. consider using v4.'
-          )
+          new Error('program too costly for version < 4. consider using v4.')
         );
       }
       //  new versions
@@ -884,7 +882,7 @@ describe('Program validation', () => {
         assert.ok(logic.checkProgram(program));
       }
     });
-    it('should support TEAL v2 opcodes', () => {
+    it('should support AVM v2 opcodes', () => {
       assert.ok(logic.langspecEvalMaxVersion >= 2);
       assert.ok(logic.langspecLogicSigVersion >= 2);
 
@@ -904,7 +902,7 @@ describe('Program validation', () => {
       result = logic.checkProgram(program);
       assert.strictEqual(result, true);
     });
-    it('should support TEAL v3 opcodes', () => {
+    it('should support AVM v3 opcodes', () => {
       assert.ok(logic.langspecEvalMaxVersion >= 3);
       assert.ok(logic.langspecLogicSigVersion >= 3);
 
@@ -954,7 +952,7 @@ describe('Program validation', () => {
       ]); // int 0; int 1; swap; pop
       assert.ok(logic.checkProgram(program));
     });
-    it('should support TEAL v4 opcodes', () => {
+    it('should support AVM v4 opcodes', () => {
       assert.ok(logic.langspecEvalMaxVersion >= 4);
 
       // divmodw
@@ -1073,7 +1071,7 @@ describe('Program validation', () => {
       ]); // int 1; loop: int 2; *; dup; int 10; <; bnz loop; int 16; ==
       assert.ok(logic.checkProgram(program));
     });
-    it('should support TEAL v5 opcodes', () => {
+    it('should support AVM v5 opcodes', () => {
       assert.ok(logic.langspecEvalMaxVersion >= 5);
 
       // itxn ops
@@ -1100,7 +1098,7 @@ describe('Program validation', () => {
       // byte "a"; byte "b"; byte "c"; cover 2; uncover 2; concat; concat; log; int 1
       assert.ok(logic.checkProgram(program));
     });
-    it('should support TEAL v6 opcodes', () => {
+    it('should support AVM v6 opcodes', () => {
       assert.ok(logic.langspecEvalMaxVersion >= 6);
 
       // bsqrt op