raffel 1.1.21 → 1.1.25-next.186fa05
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -3
- package/dist/adapters/index.d.ts +4 -0
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +4 -0
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/ssh-host-key.d.ts +17 -0
- package/dist/adapters/ssh-host-key.d.ts.map +1 -0
- package/dist/adapters/ssh-host-key.js +25 -0
- package/dist/adapters/ssh-host-key.js.map +1 -0
- package/dist/adapters/ssh-keys.d.ts +21 -0
- package/dist/adapters/ssh-keys.d.ts.map +1 -0
- package/dist/adapters/ssh-keys.js +211 -0
- package/dist/adapters/ssh-keys.js.map +1 -0
- package/dist/adapters/ssh-session.d.ts +54 -0
- package/dist/adapters/ssh-session.d.ts.map +1 -0
- package/dist/adapters/ssh-session.js +202 -0
- package/dist/adapters/ssh-session.js.map +1 -0
- package/dist/adapters/ssh-tui-bridge.d.ts +37 -0
- package/dist/adapters/ssh-tui-bridge.d.ts.map +1 -0
- package/dist/adapters/ssh-tui-bridge.js +90 -0
- package/dist/adapters/ssh-tui-bridge.js.map +1 -0
- package/dist/adapters/ssh-types.d.ts +268 -0
- package/dist/adapters/ssh-types.d.ts.map +1 -0
- package/dist/adapters/ssh-types.js +9 -0
- package/dist/adapters/ssh-types.js.map +1 -0
- package/dist/adapters/ssh.d.ts +43 -0
- package/dist/adapters/ssh.d.ts.map +1 -0
- package/dist/adapters/ssh.js +347 -0
- package/dist/adapters/ssh.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/server/builder/lifecycle-executor.d.ts.map +1 -1
- package/dist/server/builder/lifecycle-executor.js +13 -0
- package/dist/server/builder/lifecycle-executor.js.map +1 -1
- package/dist/server/fs-routes/loader.d.ts.map +1 -1
- package/dist/server/fs-routes/loader.js +173 -92
- package/dist/server/fs-routes/loader.js.map +1 -1
- package/dist/server/fs-routes/types.d.ts +70 -24
- package/dist/server/fs-routes/types.d.ts.map +1 -1
- package/dist/server/runtime-plan.d.ts +8 -0
- package/dist/server/runtime-plan.d.ts.map +1 -1
- package/dist/server/runtime-plan.js +8 -12
- package/dist/server/runtime-plan.js.map +1 -1
- package/dist/ui/server/fs-routes/loader.d.ts.map +1 -1
- package/dist/ui/server/fs-routes/types.d.ts +70 -24
- package/dist/ui/server/fs-routes/types.d.ts.map +1 -1
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# Raffel
|
|
4
4
|
|
|
5
|
-
### One server. HTTP, WebSocket, gRPC, TCP, UDP — all at once.
|
|
5
|
+
### One server. HTTP, WebSocket, gRPC, TCP, UDP, SSH — all at once.
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/raffel)
|
|
8
8
|
[](https://www.typescriptlang.org/)
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
Raffel is a TypeScript runtime for building APIs, proxies, and traffic-aware infrastructure in one stack.
|
|
19
19
|
|
|
20
|
-
- Build HTTP, WebSocket, gRPC, JSON-RPC, GraphQL, TCP, and
|
|
20
|
+
- Build HTTP, WebSocket, gRPC, JSON-RPC, GraphQL, TCP, UDP, SMTP, and SSH services with one project.
|
|
21
21
|
- Run reverse proxy, explicit proxy, CONNECT MITM, SOCKS5/SOCKS5h, and transparent proxy modes.
|
|
22
22
|
- Export service-mesh style telemetry with `source -> destination -> protocol`, p50/p90/p95, throughput, bytes, and error rates.
|
|
23
23
|
- Add resilience and policy with rate limit, retry, timeout, circuit breaker, validation, auth/session, filters, and proxy middleware.
|
|
@@ -26,7 +26,7 @@ Heavy edge features stay off by default. Telemetry, graph snapshots, Prometheus
|
|
|
26
26
|
|
|
27
27
|
Need the right guide fast? Use the docs or the built-in MCP tools: `raffel_feature_catalog`, `raffel_proxy_capabilities`, `raffel_get_guide`, and `raffel_search`.
|
|
28
28
|
|
|
29
|
-
- **Protocols:** [HTTP](https://forattini-dev.github.io/raffel/#/protocols/http), [WebSocket](https://forattini-dev.github.io/raffel/#/protocols/websocket), [gRPC](https://forattini-dev.github.io/raffel/#/protocols/grpc), [UDP](https://forattini-dev.github.io/raffel/#/protocols/udp)
|
|
29
|
+
- **Protocols:** [HTTP](https://forattini-dev.github.io/raffel/#/protocols/http), [WebSocket](https://forattini-dev.github.io/raffel/#/protocols/websocket), [gRPC](https://forattini-dev.github.io/raffel/#/protocols/grpc), [UDP](https://forattini-dev.github.io/raffel/#/protocols/udp), [SMTP](https://forattini-dev.github.io/raffel/#/protocols/smtp), [SSH](https://forattini-dev.github.io/raffel/#/protocols/ssh)
|
|
30
30
|
- **Proxies:** [Overview](https://forattini-dev.github.io/raffel/#/proxy), [Modes](https://forattini-dev.github.io/raffel/#/proxy/modes), [Routing](https://forattini-dev.github.io/raffel/#/proxy/routing), [Service Mesh](https://forattini-dev.github.io/raffel/#/proxy/service-mesh)
|
|
31
31
|
- **Observability:** [Flow Metrics](https://forattini-dev.github.io/raffel/#/proxy/flow-metrics), [Observability](https://forattini-dev.github.io/raffel/#/observability), [Tracing](https://forattini-dev.github.io/raffel/#/observability/tracing)
|
|
32
32
|
|
|
@@ -547,6 +547,58 @@ await proxy.start()
|
|
|
547
547
|
|
|
548
548
|
---
|
|
549
549
|
|
|
550
|
+
## SSH Server (TUI over `ssh your.app`)
|
|
551
|
+
|
|
552
|
+
Ship terminal apps the way [terminal.shop](https://terminal.shop) does — users
|
|
553
|
+
type `ssh your.app` and land in a real, rendered TUI. The adapter exposes raw
|
|
554
|
+
streams, parsed key events, resize handling, and an optional TTY-compatible
|
|
555
|
+
bridge for [tuiuiu.js](https://www.npmjs.com/package/tuiuiu.js) so reactive
|
|
556
|
+
components render straight into the SSH session.
|
|
557
|
+
|
|
558
|
+
```typescript
|
|
559
|
+
import { createSshAdapter } from 'raffel'
|
|
560
|
+
|
|
561
|
+
const ssh = createSshAdapter({
|
|
562
|
+
port: 2222,
|
|
563
|
+
// auth defaults to anonymous (terminal.shop style); add password/publicKey
|
|
564
|
+
// verifiers to mix public and private access in the same adapter.
|
|
565
|
+
onSession: async (session) => {
|
|
566
|
+
session.write(`☕ Hi ${session.user}!\r\n`)
|
|
567
|
+
for await (const key of session.keys) {
|
|
568
|
+
if (key.ctrl && key.name === 'c') break
|
|
569
|
+
session.write(key.str)
|
|
570
|
+
}
|
|
571
|
+
},
|
|
572
|
+
})
|
|
573
|
+
|
|
574
|
+
await ssh.start()
|
|
575
|
+
// Now: ssh -p 2222 anything@localhost
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
With **tuiuiu.js** plugged in:
|
|
579
|
+
|
|
580
|
+
```typescript
|
|
581
|
+
import { render, Box, Text } from 'tuiuiu.js'
|
|
582
|
+
|
|
583
|
+
createSshAdapter({
|
|
584
|
+
port: 2222,
|
|
585
|
+
onSession: async (session) => {
|
|
586
|
+
const app = render(
|
|
587
|
+
() => Box({}, Text({ color: 'cyan' }, `Hello, ${session.user}!`)),
|
|
588
|
+
session.tui, // TTY-compatible bridge
|
|
589
|
+
)
|
|
590
|
+
await app.waitUntilExit()
|
|
591
|
+
},
|
|
592
|
+
})
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
Install peer deps when you use the adapter: `pnpm add ssh2` (required),
|
|
596
|
+
`pnpm add tuiuiu.js` (only for reactive UIs).
|
|
597
|
+
|
|
598
|
+
Full details: [SSH protocol guide](https://forattini-dev.github.io/raffel/#/protocols/ssh).
|
|
599
|
+
|
|
600
|
+
---
|
|
601
|
+
|
|
550
602
|
## Session Store
|
|
551
603
|
|
|
552
604
|
```typescript
|
package/dist/adapters/index.d.ts
CHANGED
|
@@ -15,6 +15,10 @@ export { createGrpcAdapter } from './grpc.js';
|
|
|
15
15
|
export type { GrpcAdapter, GrpcAdapterOptions, GrpcTlsOptions, GrpcMethodInfo } from './grpc.js';
|
|
16
16
|
export { createSmtpAdapter, createSmtpClient } from './smtp.js';
|
|
17
17
|
export type { SmtpAdapter, SmtpAdapterOptions, SmtpContextCapability, SmtpTlsOptions, SmtpAuthVerifier, SmtpRecipientValidator } from './smtp.js';
|
|
18
|
+
export { createSshAdapter } from './ssh.js';
|
|
19
|
+
export { generateEphemeralHostKey } from './ssh-host-key.js';
|
|
20
|
+
export { parseKeys } from './ssh-keys.js';
|
|
21
|
+
export type { SshAdapter, SshAdapterOptions, SshAuthOptions, SshAuthHandler, SshAuthRequest, SshClientInfo, SshHostKey, SshPtyInfo, SshSession, SshSessionHandler, KeyEvent, TtyReadable, TtyWritable, } from './ssh-types.js';
|
|
18
22
|
export { checkConnectionFilter, checkWebSocketConnectionFilter } from './utils/connection-filter.js';
|
|
19
23
|
export type { ConnectionFilter, WebSocketConnectionFilter } from './utils/connection-filter.js';
|
|
20
24
|
export { validateChannelName, DEFAULT_CHANNEL_NAME_PATTERN, DEFAULT_CHANNEL_NAME_MAX_LENGTH, } from './utils/channel-name.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AACvD,YAAY,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAGpG,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAC7C,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAGhF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC5D,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAG7D,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC5D,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAG7D,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACtF,YAAY,EACV,cAAc,EACd,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,YAAY,GACb,MAAM,cAAc,CAAA;AAGrB,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAC7C,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAGhG,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AAC/D,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,cAAc,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAA;AAGjJ,OAAO,EAAE,qBAAqB,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAA;AACpG,YAAY,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAA;AAG/F,OAAO,EACL,mBAAmB,EACnB,4BAA4B,EAC5B,+BAA+B,GAChC,MAAM,yBAAyB,CAAA;AAChC,YAAY,EACV,qBAAqB,EACrB,4BAA4B,GAC7B,MAAM,yBAAyB,CAAA;AAGhC,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAA;AACzF,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AACvD,YAAY,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AAGpG,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAC7C,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAGhF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC5D,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAG7D,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC5D,YAAY,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AAG7D,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AACtF,YAAY,EACV,cAAc,EACd,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,YAAY,GACb,MAAM,cAAc,CAAA;AAGrB,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAC7C,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAGhG,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AAC/D,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,cAAc,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAA;AAGjJ,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAC3C,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAA;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AACzC,YAAY,EACV,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,cAAc,EACd,aAAa,EACb,UAAU,EACV,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,QAAQ,EACR,WAAW,EACX,WAAW,GACZ,MAAM,gBAAgB,CAAA;AAGvB,OAAO,EAAE,qBAAqB,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAA;AACpG,YAAY,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAA;AAG/F,OAAO,EACL,mBAAmB,EACnB,4BAA4B,EAC5B,+BAA+B,GAChC,MAAM,yBAAyB,CAAA;AAChC,YAAY,EACV,qBAAqB,EACrB,4BAA4B,GAC7B,MAAM,yBAAyB,CAAA;AAGhC,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAA;AACzF,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAA"}
|
package/dist/adapters/index.js
CHANGED
|
@@ -16,6 +16,10 @@ export { createJsonRpcAdapter, JsonRpcErrorCode, HttpMetadataKey } from './jsonr
|
|
|
16
16
|
export { createGrpcAdapter } from './grpc.js';
|
|
17
17
|
// SMTP adapter
|
|
18
18
|
export { createSmtpAdapter, createSmtpClient } from './smtp.js';
|
|
19
|
+
// SSH adapter
|
|
20
|
+
export { createSshAdapter } from './ssh.js';
|
|
21
|
+
export { generateEphemeralHostKey } from './ssh-host-key.js';
|
|
22
|
+
export { parseKeys } from './ssh-keys.js';
|
|
19
23
|
// Connection Filter (TCP, UDP, WebSocket)
|
|
20
24
|
export { checkConnectionFilter, checkWebSocketConnectionFilter } from './utils/connection-filter.js';
|
|
21
25
|
// Channel name validation (WebSocket subscribe/publish ingress, issue #106)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,iDAAiD;AAEjD,oBAAoB;AACpB,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AAGvD,eAAe;AACf,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAG7C,cAAc;AACd,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAG5D,cAAc;AACd,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAG5D,uBAAuB;AACvB,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAStF,eAAe;AACf,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAG7C,eAAe;AACf,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AAG/D,0CAA0C;AAC1C,OAAO,EAAE,qBAAqB,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAA;AAGpG,4EAA4E;AAC5E,OAAO,EACL,mBAAmB,EACnB,4BAA4B,EAC5B,+BAA+B,GAChC,MAAM,yBAAyB,CAAA;AAMhC,wCAAwC;AACxC,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,iDAAiD;AAEjD,oBAAoB;AACpB,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AAGvD,eAAe;AACf,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAG7C,cAAc;AACd,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAG5D,cAAc;AACd,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAG5D,uBAAuB;AACvB,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAStF,eAAe;AACf,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAG7C,eAAe;AACf,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AAG/D,cAAc;AACd,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAC3C,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAA;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAiBzC,0CAA0C;AAC1C,OAAO,EAAE,qBAAqB,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAA;AAGpG,4EAA4E;AAC5E,OAAO,EACL,mBAAmB,EACnB,4BAA4B,EAC5B,+BAA+B,GAChC,MAAM,yBAAyB,CAAA;AAMhC,wCAAwC;AACxC,OAAO,EAAE,mBAAmB,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSH Adapter — Host key utilities
|
|
3
|
+
*
|
|
4
|
+
* Auto-generates an ephemeral RSA host key for dev. For production,
|
|
5
|
+
* users should provide a persistent key via `hostKeys` so clients don't
|
|
6
|
+
* see a "host key changed" warning each restart.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Generate an ephemeral RSA 2048 private key in PEM (PKCS#1) format.
|
|
10
|
+
* Suitable for ssh2 ServerConfig.hostKeys.
|
|
11
|
+
*
|
|
12
|
+
* RSA + PKCS#1 was chosen because it is the format ssh2 parses most
|
|
13
|
+
* reliably across versions. Ed25519 in PKCS#8 (Node's default) is not
|
|
14
|
+
* accepted by ssh2's key parser.
|
|
15
|
+
*/
|
|
16
|
+
export declare function generateEphemeralHostKey(): Buffer;
|
|
17
|
+
//# sourceMappingURL=ssh-host-key.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh-host-key.d.ts","sourceRoot":"","sources":["../../src/adapters/ssh-host-key.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAOjD"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSH Adapter — Host key utilities
|
|
3
|
+
*
|
|
4
|
+
* Auto-generates an ephemeral RSA host key for dev. For production,
|
|
5
|
+
* users should provide a persistent key via `hostKeys` so clients don't
|
|
6
|
+
* see a "host key changed" warning each restart.
|
|
7
|
+
*/
|
|
8
|
+
import { generateKeyPairSync } from 'node:crypto';
|
|
9
|
+
/**
|
|
10
|
+
* Generate an ephemeral RSA 2048 private key in PEM (PKCS#1) format.
|
|
11
|
+
* Suitable for ssh2 ServerConfig.hostKeys.
|
|
12
|
+
*
|
|
13
|
+
* RSA + PKCS#1 was chosen because it is the format ssh2 parses most
|
|
14
|
+
* reliably across versions. Ed25519 in PKCS#8 (Node's default) is not
|
|
15
|
+
* accepted by ssh2's key parser.
|
|
16
|
+
*/
|
|
17
|
+
export function generateEphemeralHostKey() {
|
|
18
|
+
const { privateKey } = generateKeyPairSync('rsa', {
|
|
19
|
+
modulusLength: 2048,
|
|
20
|
+
privateKeyEncoding: { type: 'pkcs1', format: 'pem' },
|
|
21
|
+
publicKeyEncoding: { type: 'pkcs1', format: 'pem' },
|
|
22
|
+
});
|
|
23
|
+
return Buffer.from(privateKey, 'utf8');
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=ssh-host-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh-host-key.js","sourceRoot":"","sources":["../../src/adapters/ssh-host-key.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAEjD;;;;;;;GAOG;AACH,MAAM,UAAU,wBAAwB;IACtC,MAAM,EAAE,UAAU,EAAE,GAAG,mBAAmB,CAAC,KAAK,EAAE;QAChD,aAAa,EAAE,IAAI;QACnB,kBAAkB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE;QACpD,iBAAiB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE;KACpD,CAAC,CAAA;IACF,OAAO,MAAM,CAAC,IAAI,CAAC,UAAoB,EAAE,MAAM,CAAC,CAAA;AAClD,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSH Adapter — Key parser
|
|
3
|
+
*
|
|
4
|
+
* Parses raw bytes from a pty stdin into structured KeyEvent objects.
|
|
5
|
+
* Recognises common ANSI escape sequences (arrows, function keys, navigation)
|
|
6
|
+
* and ASCII control codes.
|
|
7
|
+
*
|
|
8
|
+
* Inspired by Node's internal `readline` keypress parser but kept minimal
|
|
9
|
+
* and self-contained (no readline dep, no process.stdin coupling).
|
|
10
|
+
*/
|
|
11
|
+
import type { KeyEvent } from './ssh-types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Parse one buffer chunk into zero or more KeyEvents.
|
|
14
|
+
*
|
|
15
|
+
* Best-effort: an incoming chunk may contain multiple keys (bracketed
|
|
16
|
+
* paste, key spam) and we emit them in order. An incomplete escape
|
|
17
|
+
* sequence at the end is dropped (the next chunk should re-deliver it
|
|
18
|
+
* since terminals send escape sequences in one frame in practice).
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseKeys(buf: Buffer): KeyEvent[];
|
|
21
|
+
//# sourceMappingURL=ssh-keys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh-keys.d.ts","sourceRoot":"","sources":["../../src/adapters/ssh-keys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAwC9C;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,EAAE,CAuGjD"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSH Adapter — Key parser
|
|
3
|
+
*
|
|
4
|
+
* Parses raw bytes from a pty stdin into structured KeyEvent objects.
|
|
5
|
+
* Recognises common ANSI escape sequences (arrows, function keys, navigation)
|
|
6
|
+
* and ASCII control codes.
|
|
7
|
+
*
|
|
8
|
+
* Inspired by Node's internal `readline` keypress parser but kept minimal
|
|
9
|
+
* and self-contained (no readline dep, no process.stdin coupling).
|
|
10
|
+
*/
|
|
11
|
+
const NAMED_CSI = {
|
|
12
|
+
A: 'up',
|
|
13
|
+
B: 'down',
|
|
14
|
+
C: 'right',
|
|
15
|
+
D: 'left',
|
|
16
|
+
H: 'home',
|
|
17
|
+
F: 'end',
|
|
18
|
+
// CSI ~ family
|
|
19
|
+
'2~': 'insert',
|
|
20
|
+
'3~': 'delete',
|
|
21
|
+
'5~': 'pageup',
|
|
22
|
+
'6~': 'pagedown',
|
|
23
|
+
'7~': 'home',
|
|
24
|
+
'8~': 'end',
|
|
25
|
+
'11~': 'f1',
|
|
26
|
+
'12~': 'f2',
|
|
27
|
+
'13~': 'f3',
|
|
28
|
+
'14~': 'f4',
|
|
29
|
+
'15~': 'f5',
|
|
30
|
+
'17~': 'f6',
|
|
31
|
+
'18~': 'f7',
|
|
32
|
+
'19~': 'f8',
|
|
33
|
+
'20~': 'f9',
|
|
34
|
+
'21~': 'f10',
|
|
35
|
+
'23~': 'f11',
|
|
36
|
+
'24~': 'f12',
|
|
37
|
+
};
|
|
38
|
+
// SS3 sequences (ESC O X) — common for F1-F4
|
|
39
|
+
const SS3 = {
|
|
40
|
+
P: 'f1',
|
|
41
|
+
Q: 'f2',
|
|
42
|
+
R: 'f3',
|
|
43
|
+
S: 'f4',
|
|
44
|
+
H: 'home',
|
|
45
|
+
F: 'end',
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Parse one buffer chunk into zero or more KeyEvents.
|
|
49
|
+
*
|
|
50
|
+
* Best-effort: an incoming chunk may contain multiple keys (bracketed
|
|
51
|
+
* paste, key spam) and we emit them in order. An incomplete escape
|
|
52
|
+
* sequence at the end is dropped (the next chunk should re-deliver it
|
|
53
|
+
* since terminals send escape sequences in one frame in practice).
|
|
54
|
+
*/
|
|
55
|
+
export function parseKeys(buf) {
|
|
56
|
+
const out = [];
|
|
57
|
+
let i = 0;
|
|
58
|
+
while (i < buf.length) {
|
|
59
|
+
const byte = buf[i];
|
|
60
|
+
// ESC — start of escape sequence
|
|
61
|
+
if (byte === 0x1b) {
|
|
62
|
+
// ESC alone (would be ambiguous; emit as 'escape' if it's the only byte)
|
|
63
|
+
if (i === buf.length - 1) {
|
|
64
|
+
out.push(makeKey(buf.slice(i, i + 1), { name: 'escape' }));
|
|
65
|
+
i++;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const next = buf[i + 1];
|
|
69
|
+
// ESC [ — CSI
|
|
70
|
+
if (next === 0x5b /* [ */) {
|
|
71
|
+
const end = findCsiEnd(buf, i + 2);
|
|
72
|
+
if (end === -1) {
|
|
73
|
+
// Incomplete — bail; client likely sends the rest in another chunk
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
const seq = buf.slice(i, end + 1);
|
|
77
|
+
out.push(parseCsi(seq));
|
|
78
|
+
i = end + 1;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
// ESC O — SS3
|
|
82
|
+
if (next === 0x4f /* O */ && i + 2 < buf.length) {
|
|
83
|
+
const c = String.fromCharCode(buf[i + 2]);
|
|
84
|
+
const name = SS3[c];
|
|
85
|
+
out.push(makeKey(buf.slice(i, i + 3), {
|
|
86
|
+
name,
|
|
87
|
+
sequence: `\x1bO${c}`,
|
|
88
|
+
}));
|
|
89
|
+
i += 3;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
// ESC <char> — alt+char
|
|
93
|
+
if (next >= 0x20 && next < 0x7f) {
|
|
94
|
+
const ch = String.fromCharCode(next);
|
|
95
|
+
out.push(makeKey(buf.slice(i, i + 2), {
|
|
96
|
+
str: ch,
|
|
97
|
+
name: ch.toLowerCase(),
|
|
98
|
+
meta: true,
|
|
99
|
+
shift: ch >= 'A' && ch <= 'Z',
|
|
100
|
+
}));
|
|
101
|
+
i += 2;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
// Unknown ESC sequence — drop ESC, treat next bytes normally
|
|
105
|
+
i++;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
// ASCII control codes
|
|
109
|
+
if (byte < 0x20 || byte === 0x7f) {
|
|
110
|
+
out.push(parseControl(byte, buf.slice(i, i + 1)));
|
|
111
|
+
i++;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
// UTF-8 character (single byte fast path)
|
|
115
|
+
if (byte < 0x80) {
|
|
116
|
+
const ch = String.fromCharCode(byte);
|
|
117
|
+
out.push(makeKey(buf.slice(i, i + 1), {
|
|
118
|
+
str: ch,
|
|
119
|
+
name: ch.toLowerCase(),
|
|
120
|
+
shift: ch >= 'A' && ch <= 'Z',
|
|
121
|
+
}));
|
|
122
|
+
i++;
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
// Multi-byte UTF-8 — find length
|
|
126
|
+
let len = 1;
|
|
127
|
+
if ((byte & 0xe0) === 0xc0)
|
|
128
|
+
len = 2;
|
|
129
|
+
else if ((byte & 0xf0) === 0xe0)
|
|
130
|
+
len = 3;
|
|
131
|
+
else if ((byte & 0xf8) === 0xf0)
|
|
132
|
+
len = 4;
|
|
133
|
+
if (i + len > buf.length)
|
|
134
|
+
break; // incomplete
|
|
135
|
+
const slice = buf.slice(i, i + len);
|
|
136
|
+
out.push(makeKey(slice, {
|
|
137
|
+
str: slice.toString('utf8'),
|
|
138
|
+
}));
|
|
139
|
+
i += len;
|
|
140
|
+
}
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
143
|
+
function findCsiEnd(buf, start) {
|
|
144
|
+
// CSI final byte is in range 0x40..0x7e
|
|
145
|
+
for (let i = start; i < buf.length; i++) {
|
|
146
|
+
const b = buf[i];
|
|
147
|
+
if (b >= 0x40 && b <= 0x7e)
|
|
148
|
+
return i;
|
|
149
|
+
}
|
|
150
|
+
return -1;
|
|
151
|
+
}
|
|
152
|
+
function parseCsi(seq) {
|
|
153
|
+
const str = seq.toString('ascii');
|
|
154
|
+
const params = str.slice(2, -1); // strip ESC [ and final byte
|
|
155
|
+
const final = str[str.length - 1];
|
|
156
|
+
// CSI <num>~ family (e.g. 5~ = pageup)
|
|
157
|
+
if (final === '~') {
|
|
158
|
+
const key = `${params}~`;
|
|
159
|
+
const name = NAMED_CSI[key];
|
|
160
|
+
return makeKey(seq, { name, sequence: str });
|
|
161
|
+
}
|
|
162
|
+
// CSI <letter> family (arrows, home, end)
|
|
163
|
+
// May include modifier params: ESC[1;5A means ctrl+up
|
|
164
|
+
const name = NAMED_CSI[final];
|
|
165
|
+
let ctrl = false;
|
|
166
|
+
let shift = false;
|
|
167
|
+
let meta = false;
|
|
168
|
+
if (params.includes(';')) {
|
|
169
|
+
const mod = parseInt(params.split(';')[1] ?? '1', 10) - 1;
|
|
170
|
+
if (mod & 1)
|
|
171
|
+
shift = true;
|
|
172
|
+
if (mod & 2)
|
|
173
|
+
meta = true;
|
|
174
|
+
if (mod & 4)
|
|
175
|
+
ctrl = true;
|
|
176
|
+
}
|
|
177
|
+
return makeKey(seq, { name, ctrl, shift, meta, sequence: str });
|
|
178
|
+
}
|
|
179
|
+
function parseControl(byte, raw) {
|
|
180
|
+
if (byte === 0x0d /* \r */ || byte === 0x0a /* \n */) {
|
|
181
|
+
return makeKey(raw, { name: 'return', str: '\n' });
|
|
182
|
+
}
|
|
183
|
+
if (byte === 0x09 /* \t */)
|
|
184
|
+
return makeKey(raw, { name: 'tab', str: '\t' });
|
|
185
|
+
if (byte === 0x7f)
|
|
186
|
+
return makeKey(raw, { name: 'backspace' });
|
|
187
|
+
if (byte === 0x08)
|
|
188
|
+
return makeKey(raw, { name: 'backspace', ctrl: true });
|
|
189
|
+
if (byte === 0x20 /* space */)
|
|
190
|
+
return makeKey(raw, { name: 'space', str: ' ' });
|
|
191
|
+
if (byte === 0x1b)
|
|
192
|
+
return makeKey(raw, { name: 'escape' });
|
|
193
|
+
// Ctrl+A..Ctrl+Z map to 0x01..0x1a
|
|
194
|
+
if (byte >= 0x01 && byte <= 0x1a) {
|
|
195
|
+
const letter = String.fromCharCode(0x60 + byte); // 'a' + (byte - 1)
|
|
196
|
+
return makeKey(raw, { name: letter, ctrl: true, str: letter });
|
|
197
|
+
}
|
|
198
|
+
return makeKey(raw, { sequence: `\\x${byte.toString(16).padStart(2, '0')}` });
|
|
199
|
+
}
|
|
200
|
+
function makeKey(raw, partial) {
|
|
201
|
+
return {
|
|
202
|
+
raw,
|
|
203
|
+
str: partial.str ?? '',
|
|
204
|
+
name: partial.name,
|
|
205
|
+
ctrl: partial.ctrl ?? false,
|
|
206
|
+
shift: partial.shift ?? false,
|
|
207
|
+
meta: partial.meta ?? false,
|
|
208
|
+
sequence: partial.sequence,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=ssh-keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh-keys.js","sourceRoot":"","sources":["../../src/adapters/ssh-keys.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SSH Adapter — Session factory
|
|
3
|
+
*
|
|
4
|
+
* Wraps an ssh2 ServerChannel into the user-facing SshSession surface.
|
|
5
|
+
* Owns the lifecycle: parses input keys, manages window-resize, dispatches
|
|
6
|
+
* close events, builds the lazy tuiuiu bridge.
|
|
7
|
+
*/
|
|
8
|
+
import type { Writable } from 'node:stream';
|
|
9
|
+
import type { SshClientInfo, SshPtyInfo, SshSession } from './ssh-types.js';
|
|
10
|
+
import { type TuiBridge } from './ssh-tui-bridge.js';
|
|
11
|
+
/**
|
|
12
|
+
* Minimal subset of ssh2 ServerChannel we depend on. Declared structurally
|
|
13
|
+
* so we don't need to import ssh2 types into adapter session code.
|
|
14
|
+
*/
|
|
15
|
+
export interface SshChannelLike {
|
|
16
|
+
stderr: Writable;
|
|
17
|
+
write(chunk: string | Uint8Array): boolean;
|
|
18
|
+
end(): void;
|
|
19
|
+
exit(code: number): void;
|
|
20
|
+
on(event: 'data', listener: (chunk: Buffer) => void): this;
|
|
21
|
+
on(event: 'close' | 'end', listener: () => void): this;
|
|
22
|
+
once(event: 'close' | 'end', listener: () => void): this;
|
|
23
|
+
off(event: string, listener: (...args: unknown[]) => void): this;
|
|
24
|
+
destroyed?: boolean;
|
|
25
|
+
pipe?: unknown;
|
|
26
|
+
}
|
|
27
|
+
export interface CreateSshSessionOptions {
|
|
28
|
+
id: string;
|
|
29
|
+
user: string;
|
|
30
|
+
authMethod: 'none' | 'password' | 'publickey';
|
|
31
|
+
authData: {
|
|
32
|
+
publicKey?: {
|
|
33
|
+
algo: string;
|
|
34
|
+
data: Buffer;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
client: SshClientInfo;
|
|
38
|
+
env: Record<string, string>;
|
|
39
|
+
pty: SshPtyInfo | null;
|
|
40
|
+
channel: SshChannelLike;
|
|
41
|
+
kind: 'shell' | 'exec' | 'subsystem';
|
|
42
|
+
command?: string;
|
|
43
|
+
subsystem?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface InternalSshSession extends SshSession {
|
|
46
|
+
/** Update pty size — called when the SSH client sends window-change. */
|
|
47
|
+
_updateSize(cols: number, rows: number): void;
|
|
48
|
+
/** Notify the session that the underlying channel closed. */
|
|
49
|
+
_notifyClosed(): void;
|
|
50
|
+
/** Get the tui bridge if it was created, else null (for cleanup). */
|
|
51
|
+
_tuiBridge(): TuiBridge | null;
|
|
52
|
+
}
|
|
53
|
+
export declare function createSshSession(opts: CreateSshSessionOptions): InternalSshSession;
|
|
54
|
+
//# sourceMappingURL=ssh-session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssh-session.d.ts","sourceRoot":"","sources":["../../src/adapters/ssh-session.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAY,QAAQ,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,KAAK,EAEV,aAAa,EACb,UAAU,EACV,UAAU,EAGX,MAAM,gBAAgB,CAAA;AAEvB,OAAO,EAAmB,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAErE;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,QAAQ,CAAA;IAChB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,OAAO,CAAA;IAC1C,GAAG,IAAI,IAAI,CAAA;IACX,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAA;IAC1D,EAAE,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAA;IACtD,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAA;IACxD,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,IAAI,CAAA;IAChE,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB,IAAI,CAAC,EAAE,OAAO,CAAA;CACf;AAED,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,WAAW,CAAA;IAC7C,QAAQ,EAAE;QAAE,SAAS,CAAC,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAA;IACxD,MAAM,EAAE,aAAa,CAAA;IACrB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC3B,GAAG,EAAE,UAAU,GAAG,IAAI,CAAA;IACtB,OAAO,EAAE,cAAc,CAAA;IACvB,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,WAAW,CAAA;IACpC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,wEAAwE;IACxE,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7C,6DAA6D;IAC7D,aAAa,IAAI,IAAI,CAAA;IACrB,qEAAqE;IACrE,UAAU,IAAI,SAAS,GAAG,IAAI,CAAA;CAC/B;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,uBAAuB,GAAG,kBAAkB,CAkMlF"}
|