Skip to content

Commit 0c1abbe

Browse files
port gist examples into docs
1 parent 85a6442 commit 0c1abbe

File tree

1 file changed

+209
-13
lines changed

1 file changed

+209
-13
lines changed

doc/api/repl.md

Lines changed: 209 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -911,35 +911,231 @@ possible to connect to a long-running Node.js process without restarting it.
911911

912912
### Examples
913913

914-
* Running a "full-featured" (`terminal`) REPL over
915-
a `net.Server` and `net.Socket` instance:
916-
<https://gist.github.com/TooTallNate/2209310>.
914+
#### Full-featured "terminal" REPL over `net.Server` and `net.Socket`
917915

918-
* Running a REPL instance over [`curl(1)`][]:
919-
<https://gist.github.com/TooTallNate/2053342>.
916+
This is an example on how to run a "full-featured" (terminal) REPL using
917+
[`net.Server`][] and [`net.Socket`][]
920918

921-
**Note**: This example is intended purely for educational purposes to demonstrate how
922-
Node.js REPLs can be started using different I/O streams.
923-
It should **not** be used in production environments or any context where security
924-
is a concern without additional protective measures.
925-
If you need to implement REPLs in a real-world application, consider alternative
926-
approaches that mitigate these risks, such as using secure input mechanisms and
927-
avoiding open network interfaces.
919+
The following script starts an HTTP server on port `1337` that allows
920+
clients to establish socket connections to its REPL instance.
928921

922+
```mjs
923+
// repl-server.js
924+
import repl from 'node:repl';
925+
import net from 'node:net';
926+
927+
net
928+
.createServer((socket) => {
929+
const r = repl.start({
930+
prompt: `socket ${socket.remoteAddress}:${socket.remotePort}> `,
931+
input: socket,
932+
output: socket,
933+
terminal: true,
934+
useGlobal: false,
935+
});
936+
r.on('exit', () => {
937+
socket.end();
938+
});
939+
r.context.socket = socket;
940+
})
941+
.listen(1337);
942+
```
943+
944+
```cjs
945+
// repl-server.js
946+
const repl = require('node:repl');
947+
const net = require('node:net');
948+
949+
net
950+
.createServer((socket) => {
951+
const r = repl.start({
952+
prompt: `socket ${socket.remoteAddress}:${socket.remotePort}> `,
953+
input: socket,
954+
output: socket,
955+
terminal: true,
956+
useGlobal: false,
957+
});
958+
r.on('exit', () => {
959+
socket.end();
960+
});
961+
r.context.socket = socket;
962+
})
963+
.listen(1337);
964+
```
965+
966+
While the following implements a client that can create a socket connection
967+
with the above defined server over port `1337`.
968+
969+
```mjs
970+
// repl-client.js
971+
import net from 'node:net';
972+
import process from 'node:process';
973+
974+
const sock = net.connect(1337);
975+
976+
process.stdin.pipe(sock);
977+
sock.pipe(process.stdout);
978+
979+
sock.on('connect', () => {
980+
process.stdin.resume();
981+
process.stdin.setRawMode(true);
982+
});
983+
984+
sock.on('close', () => {
985+
process.stdin.setRawMode(false);
986+
process.stdin.pause();
987+
sock.removeListener('close', done);
988+
});
989+
990+
process.stdin.on('end', () => {
991+
sock.destroy();
992+
console.log();
993+
});
994+
995+
process.stdin.on('data', (b) => {
996+
if (b.length === 1 && b[0] === 4) {
997+
process.stdin.emit('end');
998+
}
999+
});
1000+
```
1001+
1002+
```cjs
1003+
// repl-client.js
1004+
const net = require('node:net');
1005+
1006+
const sock = net.connect(1337);
1007+
1008+
process.stdin.pipe(sock);
1009+
sock.pipe(process.stdout);
1010+
1011+
sock.on('connect', () => {
1012+
process.stdin.resume();
1013+
process.stdin.setRawMode(true);
1014+
});
1015+
1016+
sock.on('close', () => {
1017+
process.stdin.setRawMode(false);
1018+
process.stdin.pause();
1019+
sock.removeListener('close', done);
1020+
});
1021+
1022+
process.stdin.on('end', () => {
1023+
sock.destroy();
1024+
console.log();
1025+
});
1026+
1027+
process.stdin.on('data', (b) => {
1028+
if (b.length === 1 && b[0] === 4) {
1029+
process.stdin.emit('end');
1030+
}
1031+
});
1032+
```
1033+
1034+
To run the example open two different terminals on your machine, start the server
1035+
with `node repl-server.js` in one terminal and `node repl-client.js` on the other.
1036+
1037+
Original code from: [gist.github.com/TooTallNate/2209310][full-featured REPL gist]
1038+
1039+
#### REPL over `curl`
1040+
1041+
This is an example on how to run a REPL instance over [`curl()`][]
1042+
1043+
The following script starts an HTTP server on port `8000` that can accept
1044+
a connection established via [`curl()`][].
1045+
1046+
```mjs
1047+
import http from 'node:http';
1048+
import repl from 'node:repl';
1049+
import { Buffer } from 'node:buffer';
1050+
1051+
const buf0 = Buffer.from([0]);
1052+
1053+
const server = http.createServer((req, res) => {
1054+
res.setHeader('content-type', 'multipart/octet-stream');
1055+
1056+
repl.start({
1057+
prompt: 'curl repl> ',
1058+
input: req,
1059+
output: res,
1060+
terminal: false,
1061+
useColors: true,
1062+
useGlobal: false,
1063+
});
1064+
1065+
// Hack to thread stdin and stdout
1066+
// simultaneously in curl's single thread
1067+
const iv = setInterval(() => {
1068+
res.write(buf0);
1069+
}, 100);
1070+
1071+
req.on('close', () => {
1072+
clearInterval(iv);
1073+
});
1074+
});
1075+
server.listen(8000);
1076+
```
1077+
1078+
```cjs
1079+
const http = require('node:http');
1080+
const repl = require('node:repl');
1081+
const buf0 = Buffer.from([0]);
1082+
1083+
const server = http.createServer((req, res) => {
1084+
res.setHeader('content-type', 'multipart/octet-stream');
1085+
1086+
repl.start({
1087+
prompt: 'curl repl> ',
1088+
input: req,
1089+
output: res,
1090+
terminal: false,
1091+
useColors: true,
1092+
useGlobal: false,
1093+
});
1094+
1095+
// Hack to thread stdin and stdout
1096+
// simultaneously in curl's single thread
1097+
const iv = setInterval(() => {
1098+
res.write(buf0);
1099+
}, 100);
1100+
1101+
req.on('close', () => {
1102+
clearInterval(iv);
1103+
});
1104+
});
1105+
server.listen(8000);
1106+
```
1107+
1108+
When the above script is running you can then use [`curl()`][] to connect to
1109+
the server and connect to its REPL instance by running `curl -sSNT. localhost:8000`
1110+
1111+
**Warning** This example is intended purely for educational purposes to demonstrate how
1112+
Node.js REPLs can be started using different I/O streams.
1113+
It should **not** be used in production environments or any context where security
1114+
is a concern without additional protective measures.
1115+
If you need to implement REPLs in a real-world application, consider alternative
1116+
approaches that mitigate these risks, such as using secure input mechanisms and
1117+
avoiding open network interfaces.
1118+
1119+
Original code from: [gist.github.com/TooTallNate/2053342][REPL over curl gist]
1120+
1121+
[REPL over curl gist]: https://gist.github.com/TooTallNate/2053342
9291122
[TTY keybindings]: readline.md#tty-keybindings
9301123
[ZSH]: https://en.wikipedia.org/wiki/Z_shell
9311124
[`'uncaughtException'`]: process.md#event-uncaughtexception
9321125
[`--no-experimental-repl-await`]: cli.md#--no-experimental-repl-await
9331126
[`ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE`]: errors.md#err_domain_cannot_set_uncaught_exception_capture
9341127
[`ERR_INVALID_REPL_INPUT`]: errors.md#err_invalid_repl_input
935-
[`curl(1)`]: https://curl.haxx.se/docs/manpage.html
1128+
[`curl()`]: https://curl.haxx.se/docs/manpage.html
9361129
[`domain`]: domain.md
9371130
[`module.builtinModules`]: module.md#modulebuiltinmodules
1131+
[`net.Server`]: net.md#class-netserver
1132+
[`net.Socket`]: net.md#class-netsocket
9381133
[`process.setUncaughtExceptionCaptureCallback()`]: process.md#processsetuncaughtexceptioncapturecallbackfn
9391134
[`readline.InterfaceCompleter`]: readline.md#use-of-the-completer-function
9401135
[`repl.ReplServer`]: #class-replserver
9411136
[`repl.start()`]: #replstartoptions
9421137
[`reverse-i-search`]: #reverse-i-search
9431138
[`util.inspect()`]: util.md#utilinspectobject-options
9441139
[custom evaluation functions]: #custom-evaluation-functions
1140+
[full-featured REPL gist]: https://gist.github.com/TooTallNate/2209310
9451141
[stream]: stream.md

0 commit comments

Comments
 (0)