{"id":13431134,"url":"https://github.com/dthree/vantage","last_synced_at":"2025-05-14T14:08:16.497Z","repository":{"id":32941908,"uuid":"36537989","full_name":"dthree/vantage","owner":"dthree","description":"Distributed, realtime CLI for live Node apps.","archived":false,"fork":false,"pushed_at":"2021-08-27T13:57:44.000Z","size":577,"stargazers_count":3433,"open_issues_count":15,"forks_count":111,"subscribers_count":58,"default_branch":"master","last_synced_at":"2025-05-09T10:41:40.644Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dthree.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-05-30T01:34:31.000Z","updated_at":"2025-04-28T15:09:52.000Z","dependencies_parsed_at":"2022-06-27T03:23:48.456Z","dependency_job_id":null,"html_url":"https://github.com/dthree/vantage","commit_stats":null,"previous_names":[],"tags_count":48,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dthree%2Fvantage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dthree%2Fvantage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dthree%2Fvantage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dthree%2Fvantage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dthree","download_url":"https://codeload.github.com/dthree/vantage/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254159691,"owners_count":22024564,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T02:01:00.772Z","updated_at":"2025-05-14T14:08:16.479Z","avatar_url":"https://github.com/dthree.png","language":"JavaScript","readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"http://i.imgur.com/NyusmRJ.png\" alt=\"vantage\" /\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://travis-ci.org/dthree/vantage.svg\" alt=\"Build Status\" /\u003e\n  \u003ca href=\"https://gitter.im/dthree/vantage?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/gitter-join%20chat-brightgreen.svg\" alt=\"Gitter\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/vantage\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/vantage.svg\" alt=\"NPM Version\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\n\u003cbr\u003e\n\n`Vantage` = `CLI` + `SSH` + `REPL` for your live node app. In one line:\n\n`require(\"vantage\")().listen(4000);`\n\n\u003cbr\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"http://i.imgur.com/ZwAxqv4.gif\" alt=\"vantage.js demo\" /\u003e\n\u003c/p\u003e\n\n* [What just happened?](#er-that-gif-im-so-confused)\n* [That's voodoo magic: show me the code](https://github.com/dthree/vantage/tree/master/examples/spiffy-gif/)\n* [Tell me more](#contents)\n\n## Contents\n\n* [Introduction](#introduction)\n* [Getting Started](#getting-started)\n  - [Tour](#tour)\n  - [Examples](#examples)\n  - [Community](#community)\n  - [Quick Start](#quick-start)\n* [API](#api)\n  - [.listen](#listenapp-options-or-callback-callback)\n  - [.banner](#bannerstring)\n  - [firewall](#firewall)\n  - [authentication](#authentication)\n* [Events](#events)\n* [Automation](#automation)\n* [Extensions](#extensions)\n* [License](#license)\n* [Footnotes](#footnotes)\n\n## Introduction\n\nVantage gives you a new perspective into your live node application not previously available.\n\nAn extension of [Vorpal](https://github.com/dthree/vorpal), Vantage turns your live Node app into a immersive CLI. Accessible remotely or locally, Vantage lets you build your own API for your application and import community extensions, introducing a new means of live diagnostics and activity for your `dev` and `prod` environments.\n\n- First-class CLI: tab completion, history, you name it.\n- Build your own API with the familiar syntax of `commander.js`.\n- SSH-like client / server setup for remote access to your live Node app.\n- Production-ready, with authentication middleware and a basic firewall.\n- Built-in REPL.\n\nUnlike any other REPL or CLI module, Vantage allows you to remotely connect to your live app and access the CLI transparently, exactly as you would in an SSH session. Vantage can connect through an unlimited number of live Node instances across multiple machines, piping commands and information to and from your local terminal. \n\nMade with :heart: by [@dthree](https://github.com/dthree).\n\n## Notice\n\nThis is now an [OPEN Open Source](http://openopensource.org/) project. I am not able to invest a significant amount of time into maintaining Vantage and so am looking for volunteers who would like to be active maintainers of the project. If you are interested, shoot me a note.\n\n## Getting Started\n\n##### Tour\n\n[This Vantage tour](https://github.com/dthree/vantage/tree/master/examples/tour) will give you a live walk-through of vantage's features.\n\n```bash\n$ npm install -g vantage\n$ vantage tour\n```\n\n##### Examples\n\n- [Standalone Vantage Server](https://github.com/dthree/vantage/tree/master/examples/server)\n- [Koa.js with Vantage](https://github.com/dthree/vantage/tree/master/examples/koa)\n- [Express.js with Vantage](https://github.com/dthree/vantage/tree/master/examples/express)\n- [Hapi.js with Vantage](https://github.com/dthree/vantage/tree/master/examples/hapi)\n- [Using the Firewall](https://github.com/dthree/vantage/tree/master/examples/firewall)\n\n##### Community\n\n- [Q\u0026A? Join Gitter Chat](https://gitter.im/dthree/vantage?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge)\n- [List of Extensions](https://github.com/dthree/vorpaljs/awesome-vorpal)\n\n##### Quick Start\n\nFirst, install `vantage` globally:\n\n```bash\n$ npm install -g vantage\n```\n\nNow, add the following to a file named `server.js`.\n\n```js\n// Create a new instance of vantage.\nvar vantage = require(\"vantage\")();\n\n// Add the command \"foo\", which logs \"bar\".\nvantage\n  .command(\"foo\")\n  .description(\"Outputs 'bar'.\")\n  .action(function(args, callback) {\n    this.log(\"bar\");\n    callback();\n  });\n  \n// Name your prompt delimiter \n// \"websvr~$\", listen on port 80 \n// and show the Vantage prompt.\nvantage\n  .delimiter(\"websvr~$\")\n  .listen(80)\n  .show();\n```\nRun `server.js`. You Node app has become a CLI.\n\n```bash\n$ node server.js\nwebsvr~$ \n```\n\nOpen another terminal. Because Vantage is listening on port 80, you can remotely connect to it:\n\n```bash\n$ vantage 80\n$ Connecting to 127.0.0.1:80 using http...\nwebsvr~$ \n```\n\nTry out your \"foo\" command.\n\n```bash\nwebsvr~$ foo\nbar\nwebsvr~$\n```\n\nNow type \"help\" to see Vantage's built in commands in addition to \"foo\":\n\n```bash\nwebsvr~$ help\n\n  Commands\n  \n    help [command]    Provides help for a given command.\n    exit [options]    Exits instance of Vantage.\n    use \u003cmodule\u003e      Installs a vantage extension in realtime.\n    vantage [server]  Connects to another application running vantage.\n    foo               Outputs \"bar\".\n\nwebsvr~$\n```\n\nThat's the basic idea. Once you get the hang of it, read on to learn some of the fancier things Vantage can do.\n\n## API\n\nVantage is an **extension** of [Vorpal](https://github.com/dthree/vorpal), and so inherits all of its properties and methods. For all command creation and CLI syntax, refer to Vorpal's API.\n\n### .listen(app, [options or callback], [callback])\n\nStarts Vantage as a server. \n\n#### Vantage as a standalone web server\n\nIf you just want it to listen on a port independent of your web application, simply pass in the port and Vantage will spawn a new HTTP server. Every time a client connects to Vantage, the connection callback will be thrown and include the `socket.io` connection object.\n\n```js\nvar vantage = new Vantage();\nvantage.listen(80, function(socket){\n  this.log(\"Accepted a connection.\")\n});\n```\n\n#### Vantage with an existing web server\n\nIf you want Vantage to listen on the same port as your web application, you can use Vantage's `listen` function in place of your existing web server's `listen` function.\n\nThis is useful when running clustered instances of your server, such as behind a reverse proxy, where every instance has a separate port that can only be accessed internally. In this way, you can hop into any running instance without having to remember a separate set of ports.\n\n##### With Koa.js\n\n```js\nvar koa = require('koa');\nvar Vantage = require('vantage');\n\nvar vantage = new Vantage();\nvar app = koa();\n\nvantage.listen(app, 80);\n```\n\n##### With Express.js\n\n```js\nvar express = require('express');\nvar Vantage = require('vantage');\n\nvar vantage = new Vantage();\nvar app = express();\n\nvantage.listen(app, 80);\n```\n\n##### With Hapi.js\n\n```js\nvar Hapi = require('hapi');\nvar Vantage = require('vantage');\n\nvar vantage = new Vantage();\nvar server = new Hapi.Server();\n\nvantage.listen(server, 80);\n\nserver.start();\n```\n\n##### With SSL / advanced options\n\nYou can pass detailed options to your web server with the second argument in place of the port. These options are the same options you would pass into your web server, with a few exceptions:\n\n- `options.port`: Tells vantage what port to listen on.\n- `options.ssl`: A boolean that tells Vantage whether to spawn an HTTP or HTTPs server.\n- `options.logActivity`: When true, a TTY acting as a Vantage server that receives a connection will log when clients log in and out of the server. Defaults to `false`.\n\nDefault HTTPs server example:\n\n```js\nvar vantage = new Vantage();\nvantage.listen(someMiddleware, {\n  port: 443,\n  ssl: true,\n  key: fs.readFileSync('./../../server.key'),\n  cert: fs.readFileSync('./../../server.crt'),\n  ca: fs.readFileSync('./../../ca.crt'),\n  requestCert: true,\n  rejectUnauthorized: false,\n});\n```\n\n### .banner(string)\n\nSets a banner for display when logging into a given Vantage server.\n\n```js\nvar banner = \n\"######################################################################\" + \n\"#                    Welcome to joescrabshack.com                    #\" + \n\"#                                                                    #\" +\n\"#              All connections are monitored and recorded            #\" + \n\"#      Disconnect IMMEDIATELY if you are not an authorized user      #\" + \n\"######################################################################\";\nvantage\n  .delimiter('appsvr:3000~$')\n  .banner(banner)\n  .listen(3000);\n```\n\n```bash\n$ vantage 3000\n$ Connecting to 127.0.0.1:3000...\n$ Connected successfully.\n######################################################################\n#                    Welcome to joescrabshack.com                    # \n#                                                                    #\n#              All connections are monitored and recorded            # \n#      Disconnect IMMEDIATELY if you are not an authorized user      # \n######################################################################\n? user: \n```\n*Note: See authentication section for auth details.*\n\n## Firewall\n\nIf your Vantage server is listening on a public-facing web port such as 80 or 443, your organization's firewall is not going to help you. This is a barebones IP firewall for limiting connections down to your internal subnets. For sensitive applications, this obviously does not replace authentication.\n\n### .firewall.policy(string)\n\nSets the default policy for the firewall to either `ACCEPT` or `REJECT`. Any request that does not match a rule will fall back to this policy. Returns `vantage.firewall`.\n\n**Defaults to `ACCEPT`.** \n\n```js\n// This will reject all remote connections.\nvantage.firewall.policy(\"REJECT\");\n```\n\n### .firewall.accept(address, [subnet])\n\nAllows a particular address / subnet to connect to Vantage. Returns `vantage.firewall`. If no arguments are passed, returns the currently-applied policy.\n\n```js\nvantage.firewall\n  .policy(\"REJECT\")\n  .accept(\"10.0.0.0/8\")\n  .accept(\"192.168.0.0\", 24);\n\nconsole.log(vantage.firewall.policy()) // -\u003e REJECT  \n```\n\n### .firewall.reject(address, [subnet])\n\nDenies access to a particular address / subnet. Returns `vantage.firewall`.\n\n```js\nvantage.firewall\n  .policy(\"ACCEPT\")\n  .reject(\"64.0.0.0\", 8)\n  .reject(\"192.168.0.0/16\");\n```\n### .firewall.rules()\n\nReturns an array of applied rules.\n\n```js\nconsole.log(vantage.firewall.rules());\n// -\u003e [{ ip: \"64.0.0.0\", subnet: 8, rule: \"REJECT\" }]\n```\n\n### .firewall.reset()\n\nReverts `vantage.firewall` to an `ACCEPT` policy and erases all rules.\n\n## Authentication\n\nVantage supports authentication strategies as middleware. It comes with a default [Basic Authentication module](https://github.com/dthree/vantage-auth-basic).\n\n### vantage.auth(middleware, options)\n\nUses a given authentication strategy. Pass the required middleware into the first variable, and any options / configuration for that middleware as given in that module's documentation into the options parameter.\n\n```js\nvar pam = require(\"vantage-auth-pam\");\nvantage.auth(pam, options);\n```\n\nVantage Basic Auth is built in, and so can be used with the \"basic\" string instead of requiring a module. \n\n```js\nvar users = [\n    { user: \"admin\", pass: \"4k#842jx!%s\" },\n    { user: \"user\", pass: \"Unicorn11\" }\n];\n\nvar vantage = require(\"vantage\")();\n\nvantage.auth(\"basic\", {\n  \"users\": users,\n  \"retry\": 3,\n  \"retryTime\": 500,\n  \"deny\": 1,\n  \"unlockTime\": 3000\n});\n```\n\n##### Security Note\n\nIf no `vantage.auth` function is declared, your app will not require authentication. As a security measure, if your `NODE_ENV` environment variable is not set to \"development\" and there is no authentication, Vantage will disallow remote connections. To permit remote connections without authentication, simply set your `NODE_ENV` to \"development\".\n\n##### Building Authentication Strategies\n\nYou can publish your own custom authentication strategies for Vantage.js as its own Node module.\n\n*I am currently looking to team up with a rocket scientist like you to build a pam-based authentication strategy for Vantage. If you are interested, send me a note!*\n\nThe format for publishing a strategy is simple:\n\n```js\n\nmodule.exports = function(vantage, options) {\n\n  // The Vantage instance is exposed through\n  // the `vantage` parameter. `options` exposes\n  // options passed in by the strategy's user, and\n  // is defined by you.\n\n  // This is where you can persist the log on state of \n  // the users attempting to log in, etc.\n\n  // You return a function, which executes\n  // in the same context as a vantage command.\n  // Every time the user attempts to connect,\n  // this function runs. In it you can prompt\n  // the user, etc.\n  return function(args, callback) {\n\n    /** \n     * Args exposes several pieces of data\n     * you can use:\n     * {\n     *   // If the user pre-passes auth data, it will be\n     *   // available here. Otherwise, prompt him for it.\n     *   user: \"admin\", \n     *   pass: \"Unicorn11\",\n     *   // This is based on socket.io's connection handshake,\n     *   // and has a lot more data than this.\n     *   handshake: { \n     *     host: \"192.168.0.1\",\n     *     port: \"800\"\n     *   }\n     * }\n     */\n\n    // Prompt user / look up credentials, etc.\n\n    // Authentication is determined by your\n    // callback: `callback(message, authenticated)`.\n\n    // Example of rejected auth.\n    callback(\"Invalid credentials.\", false);\n\n    // Example of accepted auth.\n    // callback(void 0, true);\n  }\n\n}\n\n``` \n\n## Events\n\nVantage extends `EventEmitter.prototype`. Simply use `vantage.on('event', fn)` and `vantage.emit('event', data)`. The following events are supported:\n\n##### Socket.io client / server events\n\nVantage uses `socket.io` to handle all communication between instances. The following events map to the default `socket.io` events:\n\n- `client_connect`: Maps to `connect` for `socket.io-client`.\n\n- `client_connect_error`: Maps to `connect_error` for `socket.io-client`.\n\n- `client_error`: Maps to `error` for `socket.io-client`.\n\n- `client_disconnect`: Maps to `disconnect` for `socket.io-client`.\n\n- `server_connection`: Maps to `connection` for `socket.io`.\n\n- `server_disconnect`: Maps to `disconnect` for `socket.io`.\n\n##### Vantage client / server events\n\n- `client_keypress`: Fires on keypress on local client terminal.\n\n- `client_prompt_submit`: Fires when the CLI prompt has been submitted with a command, including ''.\n\n- `client_command_executed`: Fires at the client once the command has been received back as executed.\n\n- `client_command_error`: Fires at the client if a command comes back with an error thrown.\n\n- `server_command_received`: Fires at the end-server actually executing a command receives the command.\n\n- `server_command_executed`: Fires at the end-server once the command has successfully executed.\n\n- `server_command_error`: Fires at the end-server if the command has thrown an error.\n\n## Automation\n\nVantage allows you execute your API commands from javascript synchronously, using either callbacks or promises.\n\n### .connect(server, port, [options or callback], [callback])\n\nConnects to another instance of Vantage. Returns callback or promise.\n\n```js\n// With a promise\nvantage.connect('127.0.0.1', 8001).then(function(data){\n  // ... \n}).catch(function(err){\n  console.log('Error connecting: ' + err);\n});\n\n// With a callback\nvantage.connect('127.0.0.1', 8001, function(err) {\n  if (!err) {\n    // ... connected\n  }\n});\n```\n##### Options\n\n- `ssl`: Set to true if server you are connecting to uses HTTPS.\n\n### .exec(command, [callback])\n\nExecutes an API command string. Returns a callback or Promise.\n\n```js\n// Using Promises:\nvantage.exec(\"vantage 8001\").then(function(data){\n  return vantage.exec(\"roll dough\");\n}).then(function(data){\n  return vantage.exec(\"add cheese\");\n}).then(function(data){\n  return vantage.exec(\"add pepperoni\");\n}).then(function(data){\n  return vantage.exec(\"shape crust\");\n}).then(function(data){\n  return vantage.exec(\"insert into oven\");\n}).then(function(data){\n  return vantage.exec(\"wait 480000\");\n}).then(function(data){\n  return vantage.exec(\"remove from oven\");\n}).then(function(data){\n  return vantage.exec(\"enjoy\");\n}).catch(function(err){\n  console.log(\"Error baking pizza: \" + err);\n  app.orderOut();\n});\n\n// Using callbacks:\nvantage.exec(\"vantage 8001\", function(err, data) {\n  if (!err) {\n    vantage.exec(\"bake pizza\", function(err, pizza){\n      if (!err) {\n        app.eat(pizza);\n      }\n    });\n  }\n});\n```\n\n## Extensions\n\nJust like Vorpal, Vantage supports extensions. Creating extensions is simple and is covered in Vorpal's documentation.\n\n## License\n\nMIT\n\n## Footnotes\n\n##### Er, that GIF... I'm so confused...\n\nThat's okay. Here's what happened:\n\n1. In my terminal, I started a local Node web server:\n\n```js\n$ node websvr.js\n```\n\nNormally, you would simply see what you logged, and would have no interaction with Node. Instead, Vantage gave us a prompt:\n\n```bash\nwebsvr~$ \n```\n\n2. I typed `help`, which gave me a list of all of Vantage's built-in commands as well as commands I added.\n\n3. In my `websvr.js`, I gave Vantage a command that would turn on logging *only for* web requests. By logging domains of activity, this assists productivity in debugging. To run this, I typed `debug web`, and it started logging all web requests.\n\n4. I then typed `debug off`, which disabled log output. \n\n5. By then entering the `repl` command, I entered a special REPL \"mode\" where I can access the raw javascript and objects in my application, while it's running. This is the equivalent of running `$ node` in your terminal, except it is in the context of your live application!\n\n6. Satisfied with `repl` mode, I exited out of it with the `exit` command.\n\n7. So that's nice, you can access the local Node instance in your terminal. But what about remote or daemonized applications? By using the built-in `vantage` command, I remotely connect to my Node database API listening on port `5001`, by running `vantage 127.0.0.1:5001`. \n\n8. Just like SSH, I'm now \"in\" the new instance, and my prompt changed to `dbsvr~$`.\n\n9. This server supports another Vantage mode. By typing `sql`, I enter \"sql mode\". Using this, I typed an arbitrary SQL command and it connected to my database and executed it. When done, I entered `exit`.\n\n10. I felt like checking out the latest trend on Hacker News. I typed `help` and was disappointed to find there was no `hacker-news` API command.\n\n11. Fortunately, someone made an extension for that - an NPM module called `vantage-hacker-news`. To download it and import the commands into Vantage in realtime, I typed `use vantage-hacker-news`.\n\n12. With this command, `vantage` did a temporary `npm install` on the module and loaded it into the application's memory. By typing `help` again, I can see I now have a new Vantage command registered: `hacker-news`!\n\n13. I used the command: `hacker-news --length 3`, and this showed me the top 3 items trending on Hacker News. One of them was obviously an article on the Node event loop, because Node is awesome.\n\n14. Satisfied, I typed `exit`, which brought me back to my web server.\n\n15. I then typed `exit -f` (for `--force`) to actually quit the web server, which was running locally in my terminal.\n\n* [Ah. Show me the GIF again](#)\n* [I get it, I get it. *Tell me more*](#contents)\n\n\u003cbr\u003e\n\n---\n\n\u003cbr\u003e\n\n\u003cp align=\"center\" width=\"128px\" height=\"128px\"\u003e\n  \u003cimg src=\"http://i.imgur.com/ajsjp9E.png\" alt=\"vantage.js\" /\u003e\n\u003c/p\u003e\n\n[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/dthree/vantage/trend.png)](https://bitdeli.com/free \"Bitdeli Badge\")\n","funding_links":[],"categories":["JavaScript","terminal","others","Packages","包","Projects"],"sub_categories":["Command-line apps","命令行应用"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdthree%2Fvantage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdthree%2Fvantage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdthree%2Fvantage/lists"}