diff --git a/CHANGELOG.org b/CHANGELOG.org
index d4c8bebf..b99379da 100644
--- a/CHANGELOG.org
+++ b/CHANGELOG.org
@@ -2,6 +2,10 @@
 #+STARTUP: content
 
 * Changelog
+** 0.9
+   - Added support for DAP Specification ~Reverse Requests~.
+   - Added ~vscode-js-debug~ latest Node.js, Chrome, Edge debuggers
+   - Updates for extension installations
 ** 0.8
    - [Breaking Change] Change debug provider names to match VS Code's naming: ~lldb~ to ~lldb-mi~ and ~codelldb~ to ~lldb~
    - Added ~dap-gdscript~
diff --git a/README.org b/README.org
index 74be3aa4..ee1fb63b 100644
--- a/README.org
+++ b/README.org
@@ -93,3 +93,4 @@
     support, (with some groundwork by yyoncho) runInTerminal support, various
     bug fixes.
   - [[https://github.com/factyy][Andrei Mochalov]] - Docker (debugging in containers) integration.
+  - [[https://github.com/jeff-phil][Jeffrey Phillips]] - [[https://github.com/microsoft/vscode-js-debug][vscode-js-debug]] installation and integration.
diff --git a/dap-js-debug.el b/dap-js-debug.el
new file mode 100644
index 00000000..255ea8dd
--- /dev/null
+++ b/dap-js-debug.el
@@ -0,0 +1,296 @@
+;;; dap-js-debug.el --- Debug Adapter Protocol mode for vscode-js-debug -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2023 Jeffrey Phillips
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see .
+
+;; Author: Jeffrey Phillips 
+;; Keywords: languages, debug, javascript
+;; Version: 0.1
+;; URL: https://github.com/emacs-lsp/dap-mode
+
+;;; Commentary:
+;; Adapter for microsoft/vscode-js-debug,
+;;    see: https://github.com/microsoft/vscode-js-debug
+;; Package-Requires: ((dap-mode "0.8"))
+;; Also requires vscode-js-debug v1.77.2+ which can be installed here
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'dash)
+(require 'ht)
+(require 'json)
+
+(require 'dap-mode)
+(require 'dap-utils)
+
+(defcustom dap-js-debug-path (expand-file-name "vscode/ms-vscode.js-debug"
+                                               dap-utils-extension-path)
+  "The path to ms-vscode js-debugger extension."
+  :group 'dap-js-debug
+  :type 'string)
+
+(defcustom dap-js-debug-program `("node"
+                                  ,(f-join dap-js-debug-path
+                                           "extension/dist/src/dapDebugServer.js"))
+  "The path and program for the ms-vscode js-debugger."
+  :group 'dap-js-debug
+  :type 'string)
+
+(defcustom dap-js-debug-output-telemetry t
+  "Output telemetry data from js-debug server if non-nil."
+  :group 'dap-js-debug
+  :type 'boolean)
+
+(defcustom dap-js-debug-extension-version "latest"
+  "The version of the github release found at
+https://github.com/microsoft/vscode-js-debug/releases"
+  :group 'dap-js-debug
+  :type 'string)
+
+(dap-utils-github-extension-setup-function "dap-js-debug" "microsoft" "vscode-js-debug"
+                                           dap-js-debug-extension-version
+                                           dap-js-debug-path
+                                           #'dap-js-debug-extension-build)
+
+(defun dap-js-debug-extension-build ()
+  "Callback from setup function in order to install extension node deps and compile."
+  (message "Building ms-vscode.js-debug in %s directory." dap-js-debug-path)
+  (let ((buf (get-buffer-create "*dap-js-debug extension build*"))
+        (default-directory (concat dap-js-debug-path "/extension")))
+    (async-shell-command
+     "npm install --sav-dev --force; npm run compile -- dapDebugServer" buf buf)))
+
+(cl-defun dap-js-debug-extension-update (&optional (ask-upgrade t))
+  "Check for update, and if `ask-upgrade' arg is non-nil will prompt user to upgrade."
+  (interactive)
+  (let* ((url (format dap-utils-github-extension-releases-info-url "microsoft"
+                      "vscode-js-debug" "latest"))
+         (cur-version
+          (let ((file (f-join dap-js-debug-path "extension/package.json")))
+            (when (file-exists-p file)
+              (with-temp-buffer
+                (insert-file-contents file)
+                (goto-char (point-min))
+                (cdr (assoc 'version (json-read)))))))
+         (latest-version
+          (let ((inhibit-message dap-inhibit-io))
+            (with-current-buffer
+                (if-let ((buf (url-retrieve-synchronously url t t 10)))
+                    buf ;returned
+                  (progn
+                    ;; Probably timeout
+                    (message "Problem getting latest version from: %s" url)
+                    (generate-new-buffer "*dap-js-debug-temp*")))
+              (if (/= (point-max) 1)
+                  (progn
+                    (goto-char (point-min))
+                    (re-search-forward "^$")
+                    (substring (cdr (assoc 'tag_name (json-read))) 1))
+                (progn
+                  (kill-buffer)
+                  cur-version))))))
+    (if (string= cur-version latest-version)
+        (when ask-upgrade
+          (message "ms-vscode.js-debug extension is up to date at version: %s"
+                   latest-version))
+      (let ((msg (format "Newer version (%s) of vscode/ms-vscode.js-debug exists than \
+currently installed version (%s)." latest-version cur-version)))
+        (if ask-upgrade
+            (when (y-or-n-p (concat msg " Do you want to upgrade now?"))
+              (dap-js-debug-setup t))
+          (message "%s Upgrade with `M-x dap-js-debug-extension-update'" msg))))))
+
+;; Check extension version when loading, and give a message about upgrading.
+(dap-js-debug-extension-update nil)
+
+(defun dap-js-debug--populate-start-file-args (conf)
+  "Load up the start config CONF for the debug adapter from launch.json, and default
+   required attributes if missing. See full options:
+   `https://github.com/microsoft/vscode-js-debug/blob/main/OPTIONS.md'"
+  (dap--put-if-absent conf :type "pwa-chrome")
+  (dap--put-if-absent conf :cwd (lsp-workspace-root))
+  (dap--put-if-absent conf :request "launch")
+  (dap--put-if-absent conf :console "internalConsole")
+  (dap--put-if-absent conf :name (concat (plist-get conf :type) "-js-debug"))
+  (let ((host "localhost")
+        (debug-port (dap--find-available-port)))
+    (dap--put-if-absent conf :host "localhost")
+    (dap--put-if-absent conf :debugServer debug-port)
+    (dap--put-if-absent conf :debugPort debug-port)
+    (dap--put-if-absent conf :program-to-start
+                        (if (not (file-exists-p dap-js-debug-path))
+                            (error "DAP program path: %s does not exist! \
+Install it with M-x dap-js-debug-setup." dap-js-debug-path)
+                          (format "%s %s %s"
+                                  (mapconcat 'identity dap-js-debug-program " ")
+                                  (plist-get conf :debugPort)
+                                  (plist-get conf :host)))))
+  (if (plist-member conf :url)
+      (progn
+        ;;(plist-put conf :mode "url")
+        (dap--put-if-absent conf :url (read-string
+                                       "Browse url: "
+                                       "http://localhost:3000" t))
+        (dap--put-if-absent conf :webRoot (lsp-workspace-root))))
+  (if (plist-member conf :file)
+      (if (plist-get conf :url)
+          (error "Both \"file\" and \"url\" properties are set in launch.json. \
+Choose one.")
+        (progn
+          (plist-put conf :mode "file")
+          (dap--put-if-absent conf :file
+                              (read-file-name "Select the file to open in the browser:"
+                                              nil (buffer-file-name) t)))))
+  (if (plist-member conf :program)
+      (dap--put-if-absent conf :program (read-file-name
+                                         "Select the Node.js program to run: "
+                                         nil (buffer-file-name) t)))
+  (when (string= "node-terminal" (plist-get conf :type))
+    (error "In launch.json \"node-terminal\" debug type is currently not supported."))
+  (when (string= "integratedTerminal" (plist-get conf :console))
+    (error "In launch.json \"console\":\"integratedTerminal\" not supported at this \
+time, use \"console\":\"internalConsole\" instead"))
+  (dap--put-if-absent conf
+                      :output-filter-function #'dap-js-debug--output-filter-function)
+  (unless dap-inhibit-io
+    (message "dap-js-debug--populate-start-file-args: %s" conf))
+  conf)
+
+;; Note, vscode-js-debug prefers now not using `pwa-' prefix, but still takes.
+;; Need to deprecate and replace: dap-chrome.el, dap-edge.el, dap-node.el before can
+;; remove `pwa-' here.
+(dap-register-debug-provider "pwa-node" #'dap-js-debug--populate-start-file-args)
+(dap-register-debug-provider "pwa-chrome" #'dap-js-debug--populate-start-file-args)
+(dap-register-debug-provider "pwa-msedge" #'dap-js-debug--populate-start-file-args)
+(dap-register-debug-provider "node-terminal" #'dap-js-debug--populate-start-file-args)
+;;If writing a vscode extension, probably wouldn't come to emacs.  Don't register this.
+;;(dap-register-debug-provider "pwa-extensionHost" #'dap-js-debug--populate-start-file-args)
+
+(dap-register-debug-template "Node.js Launch Program"
+                             (list :type "pwa-node"
+                                   :cwd nil
+                                   :request "launch"
+                                   :program nil
+                                   :name "Node.js Launch Program"))
+
+(dap-register-debug-template "Chrome Launch File"
+                             (list :type "pwa-chrome"
+                                   :cwd nil
+                                   :request "launch"
+                                   :file nil
+                                   :name "Chrome Launch File"))
+
+(dap-register-debug-template "Chrome Launch URL"
+                             (list :type "pwa-chrome"
+                                   :cwd nil
+                                   :request "launch"
+                                   :webRoot nil
+                                   :url nil
+                                   :name "Chrome Launch URL"))
+
+(add-hook 'dap-session-created-hook #'dap-js-debug--session-created)
+(defun dap-js-debug--session-created (debug-session)
+  "Set up so that processes won't ask about closing."
+  (when-let (proc (dap--debug-session-program-proc debug-session))
+    (set-process-query-on-exit-flag proc nil)))
+
+(defun dap-js-debug--output-filter-function (debug-session event)
+  "Output event data, including for vscode-js-debug, some useful telemetry data.
+   Future can do something more with the telemetry data than just printing."
+  (-let [(&hash "seq" "event" event-type "body") event]
+    (if (hash-table-p body)
+        (progn
+          (if (and (bound-and-true-p dap-js-debug-output-telemetry)
+                   (string= (gethash "category" body) "telemetry"))
+              (dap--print-to-output-buffer
+               debug-session (concat (dap--json-encode body) "\n"))
+            (dap--print-to-output-buffer
+             debug-session (concat (dap--output-buffer-format body) "\n")))))))
+
+(add-hook 'dap-terminated-hook #'dap-js-debug--term-parent)
+(defun dap-js-debug--term-parent (debug-session)
+  "Kill off parent process when child is disconnected."
+  (if (eq debug-session (if (boundp 'parent-debug-session) parent-debug-session nil))
+      (progn
+        (when-let (proc (dap--debug-session-program-proc debug-session))
+          (when (process-live-p proc)
+            (makunbound 'parent-debug-session)
+            (set-process-query-on-exit-flag proc nil)
+            (with-current-buffer (process-buffer proc)
+              ;; Switching mode, prevents triggering to open err file after killing proc
+              (shell-script-mode)
+              (kill-buffer))
+            (dap-delete-session debug-session)))))
+  (kill-buffer (dap--debug-session-output-buffer debug-session)))
+
+(add-hook 'dap-executed-hook #'dap-js-debug--reverse-request-handler)
+(defun dap-js-debug--reverse-request-handler (debug-session command)
+  "Callback hook to get messages from dap-mode reverse requests."
+  ;;This is set with `add-hook' above.
+  (unless dap-inhibit-io
+    (message "dap-js-debug--reverse-request-handler -> command: %s" command))
+  (pcase command
+    ((guard (string= command "startDebugging"))
+     ;; Assume current session now parent requesting start debugging in child session
+     (setq parent-debug-session debug-session)
+     (-let [(&hash "seq" "command" "arguments"
+                   (&hash "request" "configuration"
+                          (&hash? "type" "__pendingTargetId")))
+            (dap--debug-session-metadata debug-session)]
+       (-let (((&plist  :mode :url :file :webroot :program :outputCapture
+                        :skipFiles :timeout :host :name :debugPort)
+               (dap--debug-session-launch-args debug-session))
+              (conf `(:request ,request)))
+         ;; DAP Spec says not to include client variables to start child, including type
+         ;;(plist-put conf :type type)
+         (plist-put conf :name (concat type "-" command))
+         (plist-put conf :__pendingTargetId __pendingTargetId)
+         (plist-put conf :outputCapture outputCapture)
+         (plist-put conf :skipFiles skipFiles)
+         (plist-put conf :timeout timeout)
+         (plist-put conf :host host)
+         (plist-put conf :debugServer debugPort)
+         (plist-put conf :debugPort debugPort)
+         (if (or (string= "pwa-node" type) (string= "node" type))
+             (plist-put conf :program program)
+           (progn
+             (if (string= mode "file")
+                 (plist-put conf :file file)
+               (progn
+                 (plist-put conf :url url)
+                 (plist-put conf :webroot webroot)))))
+         (unless dap-inhibit-io
+           (message "dap-js-debug startDebugging conf: %s" conf))
+         (dap-start-debugging-noexpand conf)
+         ;; Remove child session if stored in list of recent/last configurations to
+         ;; allow `dap-debug-last' to work by getting parent not child.
+         (when-let ((last-conf (cdr (cl-first dap--debug-configuration)))
+                    (_ptid-equal (string= __pendingTargetId
+                                          (plist-get last-conf :__pendingTargetId))))
+           (pop dap--debug-configuration))
+         ;; success
+         (dap--send-message (dap--make-success-response seq command)
+                            (dap--resp-handler) debug-session))))
+    ;; This is really just confirmation response, but good place to ensure session
+    ;; selected
+    ("launch" (dap--switch-to-session debug-session))
+    (_
+     (unless dap-inhibit-io
+       (message "command: %s wasn't handled by dap-js-debug." command)))))
+
+(provide 'dap-js-debug)
+
+;;; dap-js-debug.el ends here
diff --git a/dap-mode.el b/dap-mode.el
index a2af6721..c01e10e0 100644
--- a/dap-mode.el
+++ b/dap-mode.el
@@ -117,7 +117,7 @@ also `dap--make-terminal-buffer'."
           (const :tag "asnyc-shell" :value dap-internal-terminal-shell)
           (function :tag "Custom function")))
 
-(defcustom dap-output-buffer-filter '("stdout" "stderr")
+(defcustom dap-output-buffer-filter '("stdout" "stderr" "console")
   "If non-nil, a list of output types to display in the debug output buffer."
   :group 'dap-mode
   :type 'list)
@@ -942,7 +942,11 @@ PARAMS are the event params.")
                              (formatted-output (if-let ((output-filter-fn (-> debug-session
                                                                               (dap--debug-session-launch-args)
                                                                               (plist-get :output-filter-function))))
-                                                   (funcall output-filter-fn formatted-output)
+                                                   (progn
+                                                     ;; Test # of params.  Consider deprecating 1 param function.
+                                                     (if (= 1 (cdr (func-arity output-filter-fn)))
+                                                         (funcall output-filter-fn formatted-output)
+                                                       (funcall output-filter-fn debug-session event)))
                                                  formatted-output)))
                   (when (or (not dap-output-buffer-filter) (member (gethash "category" body)
                                                                    dap-output-buffer-filter))
@@ -1096,7 +1100,17 @@ terminal configured (probably xterm)."
                                                             debug-session
                                                             (gethash "command" parsed-msg)))
                                     (message "Unable to find handler for %s." (pp parsed-msg))))
-                      ("request" (dap--start-process debug-session parsed-msg)))
+                      ("request"
+                       ;; These are "Reverse Requests", or requests from DAP server to client
+                       (pcase (gethash "command" parsed-msg)
+                         ("runInTerminal"
+                          (dap--start-process debug-session parsed-msg))
+                         (_
+                          (setf (dap--debug-session-metadata debug-session) parsed-msg)
+                          ;; Consider moving this hook out to also include runInTerminal reverse requests
+                          (run-hook-with-args 'dap-executed-hook
+                                              debug-session
+                                              (gethash "command" parsed-msg))))))
                   (quit))))
             (dap--parser-read parser msg)))))
 
@@ -1140,8 +1154,8 @@ etc...."
   "Create initialize message.
 ADAPTER-ID the id of the adapter."
   (list :command "initialize"
-        :arguments (list :clientID "vscode"
-                         :clientName "Visual Studio Code"
+        :arguments (list :clientID "emacs"
+                         :clientName "emacs DAP client"
                          :adapterID adapter-id
                          :pathFormat "path"
                          :linesStartAt1 t
@@ -1149,6 +1163,8 @@ ADAPTER-ID the id of the adapter."
                          :supportsVariableType t
                          :supportsVariablePaging t
                          :supportsRunInTerminalRequest t
+                         :supportsStartDebuggingRequest t
+                         :supportTerminateDebuggee t
                          :locale "en-us")
         :type "request"))
 
@@ -1201,9 +1217,9 @@ ADAPTER-ID the id of the adapter."
            (message "Failed to connect to %s:%s with error message %s"
                     host
                     port
-                    (error-message-string err))
-           (sit-for dap-connect-retry-interval)
-           (setq retries (1+ retries))))))
+                    (error-message-string err)))
+         (sleep-for dap-connect-retry-interval)
+         (setq retries (1+ retries)))))
     (or result (error "Failed to connect to port %s" port))))
 
 (defun dap--create-session (launch-args)
diff --git a/dap-utils.el b/dap-utils.el
index fe5c23c1..d71b2505 100644
--- a/dap-utils.el
+++ b/dap-utils.el
@@ -32,7 +32,6 @@
 (require 'dom)
 (require 'json)
 
-
 (defconst dap-utils--ext-unzip-script "bash -c 'mkdir -p %2$s && unzip -qq %1$s -d %2$s'"
   "Unzip script to unzip vscode extension package file.")
 
@@ -55,7 +54,7 @@
     (shell-command (format dap-utils-unzip-script temp-file dest))))
 
 (defcustom dap-utils-vscode-ext-url
-  "https://marketplace.visualstudio.com/_apis/public/gallery/publishers/%s/vsextensions/%s/%s/vspackage"
+  "https://marketplace.gallery.vsassets.io/_apis/public/gallery/publisher/%s/extension/%s/%s/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage"
   "Vscode extension template url."
   :group 'dap-utils
   :type 'string)
@@ -72,6 +71,12 @@
   :group 'dap-utils
   :type 'string)
 
+(defcustom dap-utils-github-extension-releases-info-url
+  "https://api.github.com/repos/%s/%s/releases/%s"
+  "Github extension's latest version information template url."
+  :group 'dap-utils
+  :type 'string)
+
 (defcustom dap-utils-extension-path (expand-file-name ".extension" user-emacs-directory)
   "Directory to store vscode extension."
   :group 'dap-utils
@@ -113,8 +118,6 @@ PATH is the download destination path."
 (defun dap-utils-vscode-get-installed-extension-version (path)
   "Check the version of the vscode extension installed in PATH.
 Returns nil if the extension is not installed."
-  (require 'xml)
-  (require 'dom)
   (let* ((extension-manifest (f-join path "extension.vsixmanifest")))
     (when (f-exists? extension-manifest)
       (let ((pkg-identity (dom-by-tag (xml-parse-file extension-manifest) 'Identity)))
@@ -170,11 +173,11 @@ With prefix, FORCED to redownload the extension." extension-name)))
          (message "%s: %s debug extension are not set. You can download it with M-x %s-setup"
                   ,dapfile ,extension-name ,dapfile)))))
 
-(defmacro dap-utils-github-extension-setup-function (dapfile owner repo version &optional path callback)
+(defmacro dap-utils-github-extension-setup-function (dapfile owner repo &optional version path callback)
   "Helper to create DAPFILE setup function for debug extension from github.
 OWNER is the github owner.
 REPO is the github repository.
-VERSION is the github extension version.
+VERSION is the github extension version, if not set or set to `latest' then grab latest version.
 PATH is the download destination dir.
 CALLBACK is the fn to be called after the download."
   (let* ((extension-name (concat owner "." repo))
@@ -186,13 +189,33 @@ With prefix, FORCED to redownload the extension." extension-name)))
        (defun ,(intern (format "%s-setup" dapfile)) (&optional forced)
          ,help-string
          (interactive "P")
-         (unless (and (not forced) (file-exists-p ,dest))
-           (dap-utils-get-github-extension ,owner ,repo ,version ,dest)
-           (rename-file (concat ,dest "/" (concat ,repo "-" ,version))
-                        (concat ,dest "/extension"))
-           (message "%s: Downloading done!" ,dapfile)
-           (when ,callback
-             (funcall ,callback))))
+         (if (or (not ,version)
+                 (string= "latest" ,version))
+             (progn     ; Get the latest actual version
+               (let* ((url (format dap-utils-github-extension-releases-info-url ,owner ,repo ,version)))
+                 (with-current-buffer (url-retrieve-synchronously url)
+                   (goto-char (point-min))
+                   (re-search-forward "^$")
+                   (set ',version (substring (cdr (assoc 'tag_name (json-read))) 1)))))
+           (progn       ; Check that version requested exists.
+             (let* ((url (format dap-utils-github-extension-releases-info-url
+                                 ,owner ,repo (concat "tags/v" ,version)))
+                    (status (url-http-symbol-value-in-buffer 'url-http-response-status
+                                                             (url-retrieve-synchronously url))))
+               (unless (eql 200 status)
+                 (error "Error! Extension: %s.%s version: %s returned status: %s for: %s"
+                        ,owner ,repo ,version status url)))))
+         (if (or forced (not (file-exists-p ,dest)))
+             (progn 
+               (message "Installing %s.%s version: %s to %s" ,owner ,repo ,version ,dest)
+               (dap-utils-get-github-extension ,owner ,repo ,version ,dest)
+               (rename-file (concat ,dest "/" (concat ,repo "-" ,version))
+                            (concat ,dest "/extension"))
+               (message "%s: Downloading done!" ,dapfile)
+               (when ,callback
+                 (funcall ,callback)))
+           (message "Extension %s.%s exists already in %s. Remove extension, or pass the `forced' \
+argument." ,owner ,repo ,dest)))
        (unless (file-exists-p ,dest)
          (message "%s: %s debug extension are not set. You can download it with M-x %s-setup"
                   ,dapfile ,extension-name ,dapfile)))))