Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@seneca/repl

Package Overview
Dependencies
Maintainers
4
Versions
30
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@seneca/repl - npm Package Compare versions

Comparing version 5.1.0 to 6.0.0

dist/cmds.d.ts

392

bin/seneca-repl-exec.js
#!/usr/bin/env node
/* Copyright (c) 2019 voxgig and other contributors, MIT License */
/* Copyright (c) 2019-2023 voxgig and other contributors, MIT License */
'use strict'
const Net = require('net')
const OS = require('node:os')
const FS = require('node:fs')
const Path = require('node:path')
const Net = require('node:net')
const Readline = require('node:readline')
const Http = require('node:http')
const Https = require('node:https')
const { Duplex } = require('node:stream')
const Vorpal = require('@seneca/vorpal')
const state = {
connection: {},
}
const vorpal = Vorpal({history:{ignore_mode:true}})
let host = '127.0.0.1'
let port = 30303
const connection = {}
let replAddr = process.argv[2]
let portArg = process.argv[3]
let url = 'telnet:' + host + ':' + port
let scope = 'default'
function repl(vorpal) {
vorpal
.mode('repl')
.delimiter('-> ')
.init(function(args, cb) {
if(!connection.open) {
this.log('No connection. Type `exit` and use `connect`.')
}
cb()
})
.action(function(args, callback) {
if(this.session && connection.remote_seneca) {
this.session._modeDelimiter = connection.remote_seneca + '-> '
}
// NOTE: backwards compatibility: seneca-repl localhost 30303
var cmd = args+'\n'
if (null == replAddr) {
replAddr = 'telnet://' + host + ':' + port
} else if (null != portArg) {
host = replAddr
port = parseInt(portArg)
replAddr = 'telnet://' + host + ':' + port
} else {
if (!replAddr.includes('://')) {
replAddr = 'telnet://' + replAddr
}
}
connection.sock.write(cmd)
callback()
})
// TODO: support other protocals - http endpoint,
// lambda invoke (via sub plugin @seneca/repl-aws)
try {
url = new URL(replAddr)
// console.log('URL', url)
host = url.hostname || host
port = '' === url.port ? port : parseInt(url.port)
// NOTE: use URL params for additional args
scope = url.searchParams.get('scope')
scope = null == scope || '' === scope ? 'default' : scope
} catch (e) {
console.log('# CONNECTION URL ERROR: ', e.message, replAddr)
process.exit(1)
}
function connect(vorpal) {
vorpal
.command('connect [host] [port]')
.action(function(args, callback) {
var host = args.host || 'localhost'
var port = parseInt(args.port || 30303, 10)
this.log('Connecting to '+host+':'+port+' ...')
var log = this.log.bind(this)
telnet({log:log, host:host, port:port},function(err) {
if(err) {
log(err)
}
else {
vorpal.history('seneca~'+host+'~'+port)
vorpal.exec('repl')
}
const history = []
const senecaFolder = Path.join(OS.homedir(), '.seneca')
if (!FS.existsSync(senecaFolder)) {
FS.mkdirSync(senecaFolder)
}
const historyName = encodeURIComponent(replAddr)
const historyPath = Path.join(senecaFolder, 'repl-' + historyName + '.history')
if (FS.existsSync(historyPath)) {
const lines = FS.readFileSync(historyPath).toString()
lines
.split(/[\r\n]+/)
.map((line) => (null != line && '' != line ? history.push(line) : null))
}
let historyFile = null
let spec = {
log: console.log,
url,
host,
port,
scope,
delay: 1111,
first: true,
}
class RequestStream extends Duplex {
constructor(spec, options) {
super(options)
this.spec = spec
this.buffer = []
// console.log('HTTP CTOR')
}
_write(chunk, encoding, callback) {
const cmd = chunk.toString().trim()
// console.log('HTTP WRITE', cmd)
// this.buffer.push('FOO'+String.fromCharCode(0))
// this._read()
// return callback()
const url = this.spec.url
// Determine whether to use http or https based on the URL
const httpClient = url.href.startsWith('https://') ? Https : Http
const postData = JSON.stringify({
cmd,
})
let req = httpClient
.request(
url.href,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(postData),
},
},
(response) => {
let data = ''
response.on('data', (chunk) => {
data += chunk
})
response.on('end', () => {
let res = JSON.parse(data)
// console.log('HE', data, res)
this.buffer.push(res.out + String.fromCharCode(0))
this._read()
callback()
})
},
)
.on('error', (err) => {
// console.log('HE', err)
this.buffer.push(`# ERROR: ${err}\n` + String.fromCharCode(0))
this._read()
callback()
})
})
req.write(postData)
req.end()
}
_read(size) {
// console.log('H READ')
let chunk
while ((chunk = this.buffer.shift())) {
if (!this.push(chunk)) {
break
}
}
}
}
vorpal
.delimiter('seneca: ')
.use(repl)
.use(connect)
reconnect(spec)
vorpal
.show()
if(2 < process.argv.length) {
vorpal
.exec(['connect'].concat(process.argv.slice(2)).join(' '))
function reconnect(spec) {
operate(spec, function (result) {
if (result) {
if (false === result.connect && !spec.quit && !spec.first) {
setTimeout(() => {
spec.delay = Math.min(spec.delay * 1.1, 33333)
reconnect(spec)
}, spec.delay)
} else if (result.err) {
console.log('# CONNECTION ERROR:', result.err)
}
} else {
console.log('# CONNECTION ERROR: no-result')
process.exit(1)
}
})
}
function operate(spec, done) {
state.connection.first = true
state.connection.quit = false
// state.connection.sock = Net.connect(spec.port, spec.host)
try {
state.connection.sock = connect(spec)
// console.log('SOCK', !!state.connection.sock)
} catch (err) {
// console.log('CA', err)
return done({ err })
}
state.connection.sock.on('connect', function () {
// console.log('SOCK connect')
state.connection.open = true
delete state.connection.closed
function telnet(spec, done) {
connection.first = true
connection.sock = Net.connect(spec.port, spec.host)
try {
historyFile = FS.openSync(historyPath, 'a')
} catch (e) {
// Don't save history
}
connection.sock.on('connect', function() {
connection.open = true
delete connection.closed
done()
state.connection.sock.write('hello\n')
done({ connect: true, event: 'connect' })
})
connection.sock.on('error', function(err) {
if(!connection.closed) {
done(err)
state.connection.sock.on('error', function (err) {
// console.log('CE', err)
if (state.connection.open) {
return done({ event: 'error', err })
}
})
connection.sock.on('close', function(err) {
connection.open = false
connection.closed = true
spec.log('Connection closed.')
vorpal.execSync('exit')
state.connection.sock.on('close', function (err) {
// console.log('CC', err)
if (state.connection.open) {
spec.log('\n\nConnection closed.')
}
state.connection.open = false
state.connection.closed = true
return done({
connect: false,
event: 'close',
quit: !!state.connection.quit,
})
})
connection.sock.on('data', function(buffer) {
var received = buffer.toString('ascii')
const responseChunks = []
if(connection.first) {
connection.first = false
state.connection.sock.on('data', function (chunk) {
const str = chunk.toString('ascii')
// console.log('SOCK DATA', str)
connection.remote_prompt = received
connection.remote_seneca = received
.replace(/^seneca\s+/,'')
.replace(/->.*$/,'')
if (0 < str.length && 0 === str.charCodeAt(str.length - 1)) {
responseChunks.push(str)
let received = responseChunks.join('')
received = received.substring(0, received.length - 1)
responseChunks.length = 0
spec.first = false
handleResponse(received)
} else if (0 < str.length) {
responseChunks.push(str)
}
})
spec.log('Connected to '+connection.remote_seneca)
}
else {
var rp = received.indexOf(connection.remote_prompt)
if(-1 != rp) {
received = received.substring(0,rp)
function handleResponse(received) {
if (state.connection.first) {
state.connection.first = false
let jsonstr = received.trim().replace(/[\r\n]/g, '')
jsonstr = jsonstr.substring(1, jsonstr.length - 1)
try {
state.connection.remote = JSON.parse(jsonstr)
} catch (err) {
if (received.startsWith('# ERROR')) {
console.log(received)
} else {
console.log('# HELLO ERROR: ', err.message, 'hello:', received)
}
process.exit(1)
}
state.connection.prompt = state.connection.remote.id + '> '
spec.log('Connected to Seneca:', state.connection.remote)
if (null == state.connection.readline) {
state.connection.readline = Readline.createInterface({
input: process.stdin,
output: process.stdout,
// prompt: 'QQQ',
terminal: true,
history,
historySize: Number.MAX_SAFE_INTEGER,
prompt: state.connection.prompt,
})
state.connection.readline
.on('line', (line) => {
if ('quit' === line) {
process.exit(0)
}
if (null != historyFile) {
try {
FS.appendFileSync(historyFile, line + OS.EOL)
} catch (e) {
// Don't save history
}
}
state.connection.sock.write(line + '\n')
// state.connection.readline.prompt()
})
.on('error', (err) => {
console.log('# READLINE ERROR:', err)
process.exit(1)
})
.on('close', () => {
process.exit(0)
})
} else {
state.connection.readline.setPrompt(state.connection.prompt)
}
state.connection.readline.prompt()
} else {
received = received.replace(/\n+$/, '\n')
spec.log(received)
state.connection.readline.prompt()
}
}
}
// Create a duplex stream to operate the REPL
function connect(spec) {
let duplex = null
let protocol = spec.url.protocol
if ('telnet:' === protocol) {
duplex = Net.connect(spec.port, spec.host)
} else if ('http:' === protocol || 'https:' === protocol) {
duplex = makeHttpDuplex(spec)
} else {
throw new Error(
'unknown protocol: ' + protocol + ' for url: ' + spec.url.href,
)
}
return duplex
}
// Assumes endpoint will call sys:repl,send:cmd
// POST Body is: {cmd}
function makeHttpDuplex(spec) {
let reqstream = new RequestStream(spec)
setImmediate(() => {
reqstream.emit('connect')
})
return reqstream
}
{
"name": "@seneca/repl",
"description": "Provides a client and server REPL for Seneca microservice systems.",
"version": "5.1.0",
"main": "repl.js",
"version": "6.0.0",
"main": "dist/repl.js",
"license": "MIT",

@@ -20,12 +20,14 @@ "author": "Richard Rodger (https://github.com/rjrodger)",

"scripts": {
"test": "lab -P test -v -t 75 -r console -o stdout -r html -o test/coverage.html",
"coveralls": "lab -s -P test -r lcov | coveralls",
"coverage": "lab -v -P test -t 70 -r html > coverage.html",
"prettier": "prettier --write --no-semi --single-quote *.js test/*.js",
"build": "tsc -d",
"watch": "tsc -w -d",
"test": "jest --coverage",
"test-some": "jest -t",
"test-watch": "jest --coverage --watchAll",
"prettier": "prettier --write --no-semi --single-quote bin/*.js src/*.ts test/*.js",
"doc": "seneca-doc",
"reset": "npm run clean && npm i && npm test",
"clean": "rm -rf node_modules package-lock.json yarn.lock",
"reset": "npm run clean && npm i && npm run build && npm test",
"clean": "rm -rf dist node_modules package-lock.json yarn.lock",
"repo-tag": "REPO_VERSION=`node -e \"console.log(require('./package').version)\"` && echo TAG: v$REPO_VERSION && git commit -a -m v$REPO_VERSION && git push && git tag v$REPO_VERSION && git push --tags;",
"repo-publish": "npm run clean && npm i --registry=http://registry.npmjs.org && npm run repo-publish-quick",
"repo-publish-quick": "npm run prettier && npm test && npm run repo-tag && npm publish --access public --registry=https://registry.npmjs.org"
"repo-publish-quick": "npm run prettier && npm run build && npm test && npm run repo-tag && npm publish --access public --registry=https://registry.npmjs.org"
},

@@ -42,21 +44,16 @@ "keywords": [

"dependencies": {
"@hapi/hoek": "^10.0.1",
"@seneca/vorpal": "^2.2.0",
"@hapi/hoek": "^11.0.2",
"inks": "^2.0.0"
},
"devDependencies": {
"@hapi/code": "^9.0.1",
"@hapi/joi": "^17.1.1",
"@hapi/lab": "^25.0.1",
"acorn": "^8.8.0",
"async": "^3.2.4",
"coveralls": "^3.1.1",
"gex": "^4.0.1",
"prettier": "^2.7.1",
"seneca": "plugin",
"@seneca/maintain": "^0.1.0",
"@seneca/entity-util": "^1.4.0",
"jest": "^29.6.2",
"prettier": "^3.0.0",
"seneca": "^3.32.0",
"seneca-doc": "^2.1.3",
"seneca-entity": "^18.4.0",
"seneca-mem-store": "^7.0.1",
"seneca-plugin-validator": "0.6.1",
"seneca-promisify": "^3.4.0"
"seneca-entity": "^24.0.0",
"seneca-mem-store": "^8.3.0",
"seneca-promisify": "^3.6.0",
"typescript": "5.1.6"
},

@@ -66,5 +63,5 @@ "files": [

"README.md",
"repl.js",
"dist",
"bin/seneca-repl-exec.js"
]
}
![Seneca](http://senecajs.org/files/assets/seneca-logo.png)
> A [Seneca.js][] plugin
## NOTE: [Version 2 Plan](doc/version-2.md)
# seneca-repl

@@ -10,2 +14,5 @@ [![npm version][npm-badge]][npm-url]

| ![Voxgig](https://www.voxgig.com/res/img/vgt01r.png) | This open source module is sponsored and supported by [Voxgig](https://www.voxgig.com). |
|---|---|
### Seneca compatibility

@@ -12,0 +19,0 @@ Supports Seneca versions **3.x** and higher.

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc