Skip to content

Commit b396991

Browse files
doc: clarify examples section in REPL doc
The current examples presented at the bottom of the REPL doc have two issues: - they look like they're part of the section above (on how to run multiple REPL instances in the same process) but they are not - the alert informing readers not to use the second example in production environments can be wrongly interpreted as to refer to both examples The changes here address both these issues PR-URL: #57762 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]>
1 parent 1e95107 commit b396991

File tree

1 file changed

+181
-7
lines changed

1 file changed

+181
-7
lines changed

doc/api/repl.md

Lines changed: 181 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -909,30 +909,204 @@ to connect to both Unix and TCP sockets.
909909
By starting a REPL from a Unix socket-based server instead of stdin, it is
910910
possible to connect to a long-running Node.js process without restarting it.
911911

912-
For an example of running a "full-featured" (`terminal`) REPL over
913-
a `net.Server` and `net.Socket` instance, see:
914-
<https://gist.github.com/TooTallNate/2209310>.
912+
### Examples
915913

916-
For an example of running a REPL instance over [`curl(1)`][], see:
917-
<https://gist.github.com/TooTallNate/2053342>.
914+
#### Full-featured "terminal" REPL over `net.Server` and `net.Socket`
918915

919-
This example is intended purely for educational purposes to demonstrate how
916+
This is an example on how to run a "full-featured" (terminal) REPL using
917+
[`net.Server`][] and [`net.Socket`][]
918+
919+
The following script starts an HTTP server on port `1337` that allows
920+
clients to establish socket connections to its REPL instance.
921+
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 <https://gist.github.com/TooTallNate/2209310>.
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+
1050+
const server = http.createServer((req, res) => {
1051+
res.setHeader('content-type', 'multipart/octet-stream');
1052+
1053+
repl.start({
1054+
prompt: 'curl repl> ',
1055+
input: req,
1056+
output: res,
1057+
terminal: false,
1058+
useColors: true,
1059+
useGlobal: false,
1060+
});
1061+
});
1062+
1063+
server.listen(8000);
1064+
```
1065+
1066+
```cjs
1067+
const http = require('node:http');
1068+
const repl = require('node:repl');
1069+
1070+
const server = http.createServer((req, res) => {
1071+
res.setHeader('content-type', 'multipart/octet-stream');
1072+
1073+
repl.start({
1074+
prompt: 'curl repl> ',
1075+
input: req,
1076+
output: res,
1077+
terminal: false,
1078+
useColors: true,
1079+
useGlobal: false,
1080+
});
1081+
});
1082+
1083+
server.listen(8000);
1084+
```
1085+
1086+
When the above script is running you can then use [`curl()`][] to connect to
1087+
the server and connect to its REPL instance by running `curl --no-progress-meter -sSNT. localhost:8000`.
1088+
1089+
**Warning** This example is intended purely for educational purposes to demonstrate how
9201090
Node.js REPLs can be started using different I/O streams.
9211091
It should **not** be used in production environments or any context where security
9221092
is a concern without additional protective measures.
9231093
If you need to implement REPLs in a real-world application, consider alternative
9241094
approaches that mitigate these risks, such as using secure input mechanisms and
9251095
avoiding open network interfaces.
9261096

1097+
Original code from <https://gist.github.com/TooTallNate/2053342>.
1098+
9271099
[TTY keybindings]: readline.md#tty-keybindings
9281100
[ZSH]: https://en.wikipedia.org/wiki/Z_shell
9291101
[`'uncaughtException'`]: process.md#event-uncaughtexception
9301102
[`--no-experimental-repl-await`]: cli.md#--no-experimental-repl-await
9311103
[`ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE`]: errors.md#err_domain_cannot_set_uncaught_exception_capture
9321104
[`ERR_INVALID_REPL_INPUT`]: errors.md#err_invalid_repl_input
933-
[`curl(1)`]: https://curl.haxx.se/docs/manpage.html
1105+
[`curl()`]: https://curl.haxx.se/docs/manpage.html
9341106
[`domain`]: domain.md
9351107
[`module.builtinModules`]: module.md#modulebuiltinmodules
1108+
[`net.Server`]: net.md#class-netserver
1109+
[`net.Socket`]: net.md#class-netsocket
9361110
[`process.setUncaughtExceptionCaptureCallback()`]: process.md#processsetuncaughtexceptioncapturecallbackfn
9371111
[`readline.InterfaceCompleter`]: readline.md#use-of-the-completer-function
9381112
[`repl.ReplServer`]: #class-replserver

0 commit comments

Comments
 (0)