Add verified Ktor-backed networking modules to lyngio
This commit is contained in:
1 parent
f168e9f6ed
commit
d409a4bb8b
35 files changed
+4025
-23
No files matched your search
@@ -82,8 +82,11 @@ Requires installing `lyngio` into the import manager from host code.
|
||||
- `import lyng.io.fs` (filesystem `Path` API)
|
||||
- `import lyng.io.process` (process execution API)
|
||||
- `import lyng.io.console` (console capabilities, geometry, ANSI/output, events)
|
||||
- `import lyng.io.http` (HTTP/HTTPS client API)
|
||||
- `import lyng.io.ws` (WebSocket client API; currently supported on JVM, capability-gated elsewhere)
|
||||
- `import lyng.io.net` (TCP/UDP transport API; currently supported on JVM, capability-gated elsewhere)
|
||||
|
||||
## 7. AI Generation Tips
|
||||
- Assume `lyng.stdlib` APIs exist in regular script contexts.
|
||||
- For platform-sensitive code (`fs`, `process`, `console`), gate assumptions and mention required module install.
|
||||
- For platform-sensitive code (`fs`, `process`, `console`, `http`, `ws`, `net`), gate assumptions and mention required module install.
|
||||
- Prefer extension-method style (`items.filter { ... }`) and standard scope helpers (`let`/`also`/`apply`/`run`).
|
||||
@@ -0,0 +1,169 @@
|
||||
### lyng.io.http — HTTP/HTTPS client for Lyng scripts
|
||||
|
||||
This module provides a compact HTTP client API for Lyng scripts. It is implemented in `lyngio` and backed by Ktor on supported runtimes.
|
||||
|
||||
> **Note:** `lyngio` is a separate library module. It must be explicitly added as a dependency to your host application and initialized in your Lyng scopes.
|
||||
|
||||
---
|
||||
|
||||
#### Add the library to your project (Gradle)
|
||||
|
||||
If you use this repository as a multi-module project, add a dependency on `:lyngio`:
|
||||
|
||||
```kotlin
|
||||
dependencies {
|
||||
implementation("net.sergeych:lyngio:0.0.1-SNAPSHOT")
|
||||
}
|
||||
```
|
||||
|
||||
For external projects, ensure you also use the Lyng Maven repository described in `lyng.io.fs`.
|
||||
|
||||
---
|
||||
|
||||
#### Install the module into a Lyng session
|
||||
|
||||
The HTTP module is not installed automatically. Install it into the session scope and provide a policy.
|
||||
|
||||
Kotlin (host) bootstrap example:
|
||||
|
||||
```kotlin
|
||||
import net.sergeych.lyng.EvalSession
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.io.http.createHttpModule
|
||||
import net.sergeych.lyngio.http.security.PermitAllHttpAccessPolicy
|
||||
|
||||
suspend fun bootstrapHttp() {
|
||||
val session = EvalSession()
|
||||
val scope: Scope = session.getScope()
|
||||
createHttpModule(PermitAllHttpAccessPolicy, scope)
|
||||
session.eval("import lyng.io.http")
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Using from Lyng scripts
|
||||
|
||||
Simple GET:
|
||||
|
||||
import lyng.io.http
|
||||
|
||||
val r = Http.get(HTTP_TEST_URL + "/hello")
|
||||
[r.status, r.text()]
|
||||
>>> [200,hello from test]
|
||||
|
||||
Headers and response header access:
|
||||
|
||||
import lyng.io.http
|
||||
|
||||
val r = Http.get(HTTP_TEST_URL + "/headers")
|
||||
[r.headers["X-Reply"], r.headers.getAll("X-Reply").size, r.text()]
|
||||
>>> [one,2,header demo]
|
||||
|
||||
Programmatic request object:
|
||||
|
||||
import lyng.io.http
|
||||
|
||||
val q = HttpRequest()
|
||||
q.method = "POST"
|
||||
q.url = HTTP_TEST_URL + "/echo"
|
||||
q.headers = Map("Content-Type" => "text/plain")
|
||||
q.bodyText = "ping"
|
||||
|
||||
val r = Http.request(q)
|
||||
r.text()
|
||||
>>> "POST:ping"
|
||||
|
||||
HTTPS GET:
|
||||
|
||||
import lyng.io.http
|
||||
|
||||
val r = Http.get(HTTPS_TEST_URL + "/hello")
|
||||
[r.status, r.text()]
|
||||
>>> [200,hello from test]
|
||||
|
||||
---
|
||||
|
||||
#### API reference
|
||||
|
||||
##### `Http` (static methods)
|
||||
|
||||
- `isSupported(): Bool` — Whether HTTP client support is available on the current runtime.
|
||||
- `request(req: HttpRequest): HttpResponse` — Execute a request described by a mutable request object.
|
||||
- `get(url: String, headers...): HttpResponse` — Convenience GET request.
|
||||
- `post(url: String, bodyText: String = "", contentType: String? = null, headers...): HttpResponse` — Convenience text POST request.
|
||||
- `postBytes(url: String, body: Buffer, contentType: String? = null, headers...): HttpResponse` — Convenience binary POST request.
|
||||
|
||||
For convenience methods, `headers...` accepts:
|
||||
|
||||
- `MapEntry`, e.g. `"Accept" => "text/plain"`
|
||||
- 2-item lists, e.g. `["Accept", "text/plain"]`
|
||||
|
||||
##### `HttpRequest`
|
||||
|
||||
- `method: String`
|
||||
- `url: String`
|
||||
- `headers: Map<String, String>`
|
||||
- `bodyText: String?`
|
||||
- `bodyBytes: Buffer?`
|
||||
- `timeoutMillis: Int?`
|
||||
|
||||
Only one of `bodyText` and `bodyBytes` should be set.
|
||||
|
||||
##### `HttpResponse`
|
||||
|
||||
- `status: Int`
|
||||
- `statusText: String`
|
||||
- `headers: HttpHeaders`
|
||||
- `text(): String`
|
||||
- `bytes(): Buffer`
|
||||
|
||||
Response body decoding is cached inside the response object.
|
||||
|
||||
##### `HttpHeaders`
|
||||
|
||||
`HttpHeaders` behaves like `Map<String, String>` for the first value of each header name and additionally exposes:
|
||||
|
||||
- `get(name: String): String?`
|
||||
- `getAll(name: String): List<String>`
|
||||
- `names(): List<String>`
|
||||
|
||||
Header lookup is case-insensitive.
|
||||
|
||||
---
|
||||
|
||||
#### Security policy
|
||||
|
||||
The module uses `HttpAccessPolicy` to authorize requests before they are sent.
|
||||
|
||||
- `HttpAccessPolicy` — interface for custom policies
|
||||
- `PermitAllHttpAccessPolicy` — allows all requests
|
||||
- `HttpAccessOp.Request(method, url)` — operation checked by the policy
|
||||
|
||||
Example restricted policy in Kotlin:
|
||||
|
||||
```kotlin
|
||||
import net.sergeych.lyngio.fs.security.AccessContext
|
||||
import net.sergeych.lyngio.fs.security.AccessDecision
|
||||
import net.sergeych.lyngio.fs.security.Decision
|
||||
import net.sergeych.lyngio.http.security.HttpAccessOp
|
||||
import net.sergeych.lyngio.http.security.HttpAccessPolicy
|
||||
|
||||
val allowLocalOnly = object : HttpAccessPolicy {
|
||||
override suspend fun check(op: HttpAccessOp, ctx: AccessContext): AccessDecision =
|
||||
when (op) {
|
||||
is HttpAccessOp.Request ->
|
||||
if (op.url.startsWith("http://127.0.0.1:") || op.url.startsWith("http://localhost:"))
|
||||
AccessDecision(Decision.Allow)
|
||||
else
|
||||
AccessDecision(Decision.Deny, "only local HTTP requests are allowed")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Platform support
|
||||
|
||||
- **JVM:** supported
|
||||
- **Other targets:** implementation may be added later; use `Http.isSupported()` before relying on it
|
||||
@@ -0,0 +1,164 @@
|
||||
### lyng.io.net — TCP and UDP sockets for Lyng scripts
|
||||
|
||||
This module provides minimal raw transport networking for Lyng scripts. It is implemented in `lyngio` and currently backed by Ktor sockets on the JVM.
|
||||
|
||||
> **Note:** `lyngio` is a separate library module. It must be explicitly added as a dependency to your host application and initialized in your Lyng scopes.
|
||||
|
||||
---
|
||||
|
||||
#### Install the module into a Lyng session
|
||||
|
||||
Kotlin (host) bootstrap example:
|
||||
|
||||
```kotlin
|
||||
import net.sergeych.lyng.EvalSession
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.io.net.createNetModule
|
||||
import net.sergeych.lyngio.net.security.PermitAllNetAccessPolicy
|
||||
|
||||
suspend fun bootstrapNet() {
|
||||
val session = EvalSession()
|
||||
val scope: Scope = session.getScope()
|
||||
createNetModule(PermitAllNetAccessPolicy, scope)
|
||||
session.eval("import lyng.io.net")
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Using from Lyng scripts
|
||||
|
||||
Capability checks and address resolution:
|
||||
|
||||
import lyng.io.net
|
||||
|
||||
val a: SocketAddress = Net.resolve("127.0.0.1", 4040)[0]
|
||||
[Net.isSupported(), a.toString(), a.resolved, a.ipVersion == IpVersion.IPV4]
|
||||
>>> [true,127.0.0.1:4040,true,true]
|
||||
|
||||
TCP client connect, write, read, and close:
|
||||
|
||||
import lyng.buffer
|
||||
import lyng.io.net
|
||||
|
||||
val socket = Net.tcpConnect("127.0.0.1", NET_TEST_TCP_PORT)
|
||||
socket.writeUtf8("ping")
|
||||
socket.flush()
|
||||
val reply = (socket.read(16) as Buffer).decodeUtf8()
|
||||
socket.close()
|
||||
reply
|
||||
>>> "reply:ping"
|
||||
|
||||
Lyng TCP server socket operations with `tcpListen()` and `accept()`:
|
||||
|
||||
import lyng.buffer
|
||||
import lyng.io.net
|
||||
|
||||
val server = Net.tcpListen(0, "127.0.0.1")
|
||||
val port = server.localAddress().port
|
||||
val accepted = launch {
|
||||
val client = server.accept()
|
||||
val line = (client.read(4) as Buffer).decodeUtf8()
|
||||
client.writeUtf8("echo:" + line)
|
||||
client.flush()
|
||||
client.close()
|
||||
server.close()
|
||||
line
|
||||
}
|
||||
|
||||
val socket = Net.tcpConnect("127.0.0.1", port)
|
||||
socket.writeUtf8("ping")
|
||||
socket.flush()
|
||||
val reply = (socket.read(16) as Buffer).decodeUtf8()
|
||||
socket.close()
|
||||
[accepted.await(), reply]
|
||||
>>> [ping,echo:ping]
|
||||
|
||||
UDP bind, send, receive, and inspect sender address:
|
||||
|
||||
import lyng.buffer
|
||||
import lyng.io.net
|
||||
|
||||
val server = Net.udpBind(0, "127.0.0.1")
|
||||
val client = Net.udpBind(0, "127.0.0.1")
|
||||
client.send(Buffer("ping"), "127.0.0.1", server.localAddress().port)
|
||||
val d = server.receive()
|
||||
client.close()
|
||||
server.close()
|
||||
[d.data.decodeUtf8(), d.address.port > 0]
|
||||
>>> [ping,true]
|
||||
|
||||
---
|
||||
|
||||
#### API reference
|
||||
|
||||
##### `Net` (static methods)
|
||||
|
||||
- `isSupported(): Bool` — Whether any raw networking support is available.
|
||||
- `isTcpAvailable(): Bool` — Whether outbound TCP sockets are available.
|
||||
- `isTcpServerAvailable(): Bool` — Whether listening TCP server sockets are available.
|
||||
- `isUdpAvailable(): Bool` — Whether UDP datagram sockets are available.
|
||||
- `resolve(host: String, port: Int): List<SocketAddress>` — Resolve a host and port into concrete addresses.
|
||||
- `tcpConnect(host: String, port: Int, timeoutMillis: Int? = null, noDelay: Bool = true): TcpSocket` — Open an outbound TCP socket.
|
||||
- `tcpListen(port: Int, host: String? = null, backlog: Int = 128, reuseAddress: Bool = true): TcpServer` — Start a listening TCP server socket.
|
||||
- `udpBind(port: Int = 0, host: String? = null, reuseAddress: Bool = true): UdpSocket` — Bind a UDP socket.
|
||||
|
||||
##### `SocketAddress`
|
||||
|
||||
- `host: String`
|
||||
- `port: Int`
|
||||
- `ipVersion: IpVersion`
|
||||
- `resolved: Bool`
|
||||
- `toString(): String`
|
||||
|
||||
##### `TcpSocket`
|
||||
|
||||
- `isOpen(): Bool`
|
||||
- `localAddress(): SocketAddress`
|
||||
- `remoteAddress(): SocketAddress`
|
||||
- `read(maxBytes: Int = 65536): Buffer?`
|
||||
- `readLine(): String?`
|
||||
- `write(data: Buffer): void`
|
||||
- `writeUtf8(text: String): void`
|
||||
- `flush(): void`
|
||||
- `close(): void`
|
||||
|
||||
##### `TcpServer`
|
||||
|
||||
- `isOpen(): Bool`
|
||||
- `localAddress(): SocketAddress`
|
||||
- `accept(): TcpSocket`
|
||||
- `close(): void`
|
||||
|
||||
##### `UdpSocket`
|
||||
|
||||
- `isOpen(): Bool`
|
||||
- `localAddress(): SocketAddress`
|
||||
- `receive(maxBytes: Int = 65536): Datagram?`
|
||||
- `send(data: Buffer, host: String, port: Int): void`
|
||||
- `close(): void`
|
||||
|
||||
##### `Datagram`
|
||||
|
||||
- `data: Buffer`
|
||||
- `address: SocketAddress`
|
||||
|
||||
---
|
||||
|
||||
#### Security policy
|
||||
|
||||
The module uses `NetAccessPolicy` to authorize network operations before they are executed.
|
||||
|
||||
- `NetAccessPolicy` — interface for custom policies
|
||||
- `PermitAllNetAccessPolicy` — allows all network operations
|
||||
- `NetAccessOp.Resolve(host, port)`
|
||||
- `NetAccessOp.TcpConnect(host, port)`
|
||||
- `NetAccessOp.TcpListen(host, port, backlog)`
|
||||
- `NetAccessOp.UdpBind(host, port)`
|
||||
|
||||
---
|
||||
|
||||
#### Platform support
|
||||
|
||||
- **JVM:** supported
|
||||
- **Other targets:** currently report unsupported; use capability checks before relying on raw sockets
|
||||
@@ -0,0 +1,115 @@
|
||||
### lyng.io.ws — WebSocket client for Lyng scripts
|
||||
|
||||
This module provides a compact WebSocket client API for Lyng scripts. It is implemented in `lyngio` and currently backed by Ktor WebSockets on the JVM.
|
||||
|
||||
> **Note:** `lyngio` is a separate library module. It must be explicitly added as a dependency to your host application and initialized in your Lyng scopes.
|
||||
|
||||
---
|
||||
|
||||
#### Install the module into a Lyng session
|
||||
|
||||
Kotlin (host) bootstrap example:
|
||||
|
||||
```kotlin
|
||||
import net.sergeych.lyng.EvalSession
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.io.ws.createWsModule
|
||||
import net.sergeych.lyngio.ws.security.PermitAllWsAccessPolicy
|
||||
|
||||
suspend fun bootstrapWs() {
|
||||
val session = EvalSession()
|
||||
val scope: Scope = session.getScope()
|
||||
createWsModule(PermitAllWsAccessPolicy, scope)
|
||||
session.eval("import lyng.io.ws")
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Using from Lyng scripts
|
||||
|
||||
Simple text message exchange:
|
||||
|
||||
import lyng.io.ws
|
||||
|
||||
val ws = Ws.connect(WS_TEST_URL)
|
||||
ws.sendText("ping")
|
||||
val m: WsMessage = ws.receive()
|
||||
ws.close()
|
||||
[ws.url() == WS_TEST_URL, m.isText, m.text]
|
||||
>>> [true,true,echo:ping]
|
||||
|
||||
Binary message exchange:
|
||||
|
||||
import lyng.buffer
|
||||
import lyng.io.ws
|
||||
|
||||
val ws = Ws.connect(WS_TEST_BINARY_URL)
|
||||
ws.sendBytes(Buffer(9, 8, 7))
|
||||
val m: WsMessage = ws.receive()
|
||||
ws.close()
|
||||
[m.isText, (m.data as Buffer).hex]
|
||||
>>> [false,010203090807]
|
||||
|
||||
Secure websocket (`wss`) exchange:
|
||||
|
||||
import lyng.io.ws
|
||||
|
||||
val ws = Ws.connect(WSS_TEST_URL)
|
||||
ws.sendText("ping")
|
||||
val m: WsMessage = ws.receive()
|
||||
ws.close()
|
||||
[ws.url() == WSS_TEST_URL, m.text]
|
||||
>>> [true,secure:ping]
|
||||
|
||||
---
|
||||
|
||||
#### API reference
|
||||
|
||||
##### `Ws` (static methods)
|
||||
|
||||
- `isSupported(): Bool` — Whether WebSocket client support is available on the current runtime.
|
||||
- `connect(url: String, headers...): WsSession` — Open a client websocket session.
|
||||
|
||||
`headers...` accepts:
|
||||
|
||||
- `MapEntry`, e.g. `"Authorization" => "Bearer x"`
|
||||
- 2-item lists, e.g. `["Authorization", "Bearer x"]`
|
||||
|
||||
##### `WsSession`
|
||||
|
||||
- `isOpen(): Bool`
|
||||
- `url(): String`
|
||||
- `sendText(text: String): void`
|
||||
- `sendBytes(data: Buffer): void`
|
||||
- `receive(): WsMessage?`
|
||||
- `close(code: Int = 1000, reason: String = ""): void`
|
||||
|
||||
`receive()` returns `null` after a clean close.
|
||||
|
||||
##### `WsMessage`
|
||||
|
||||
- `isText: Bool`
|
||||
- `text: String?`
|
||||
- `data: Buffer?`
|
||||
|
||||
Text messages populate `text`; binary messages populate `data`.
|
||||
|
||||
---
|
||||
|
||||
#### Security policy
|
||||
|
||||
The module uses `WsAccessPolicy` to authorize websocket operations.
|
||||
|
||||
- `WsAccessPolicy` — interface for custom policies
|
||||
- `PermitAllWsAccessPolicy` — allows all websocket operations
|
||||
- `WsAccessOp.Connect(url)`
|
||||
- `WsAccessOp.Send(url, bytes, isText)`
|
||||
- `WsAccessOp.Receive(url)`
|
||||
|
||||
---
|
||||
|
||||
#### Platform support
|
||||
|
||||
- **JVM:** supported
|
||||
- **Other targets:** currently report unsupported; use `Ws.isSupported()` before relying on websocket client access
|
||||
+32
-8
@@ -13,6 +13,9 @@
|
||||
- **[lyng.io.fs](lyng.io.fs.md):** Async filesystem access. Provides the `Path` class for file/directory operations, streaming, and globbing.
|
||||
- **[lyng.io.process](lyng.io.process.md):** External process execution and shell commands. Provides `Process`, `RunningProcess`, and `Platform` information.
|
||||
- **[lyng.io.console](lyng.io.console.md):** Rich console/TTY access. Provides `Console` capability detection, geometry, output, and iterable events.
|
||||
- **[lyng.io.http](lyng.io.http.md):** HTTP/HTTPS client access. Provides `Http`, `HttpRequest`, `HttpResponse`, and `HttpHeaders`.
|
||||
- **[lyng.io.ws](lyng.io.ws.md):** WebSocket client access. Provides `Ws`, `WsSession`, and `WsMessage`.
|
||||
- **[lyng.io.net](lyng.io.net.md):** Transport networking. Provides `Net`, `TcpSocket`, `TcpServer`, `UdpSocket`, and `SocketAddress`.
|
||||
|
||||
---
|
||||
|
||||
@@ -41,9 +44,15 @@ import net.sergeych.lyng.EvalSession
|
||||
import net.sergeych.lyng.io.fs.createFs
|
||||
import net.sergeych.lyng.io.process.createProcessModule
|
||||
import net.sergeych.lyng.io.console.createConsoleModule
|
||||
import net.sergeych.lyng.io.http.createHttpModule
|
||||
import net.sergeych.lyng.io.net.createNetModule
|
||||
import net.sergeych.lyng.io.ws.createWsModule
|
||||
import net.sergeych.lyngio.fs.security.PermitAllAccessPolicy
|
||||
import net.sergeych.lyngio.process.security.PermitAllProcessAccessPolicy
|
||||
import net.sergeych.lyngio.console.security.PermitAllConsoleAccessPolicy
|
||||
import net.sergeych.lyngio.http.security.PermitAllHttpAccessPolicy
|
||||
import net.sergeych.lyngio.net.security.PermitAllNetAccessPolicy
|
||||
import net.sergeych.lyngio.ws.security.PermitAllWsAccessPolicy
|
||||
|
||||
suspend fun runMyScript() {
|
||||
val session = EvalSession()
|
||||
@@ -53,16 +62,25 @@ suspend fun runMyScript() {
|
||||
createFs(PermitAllAccessPolicy, scope)
|
||||
createProcessModule(PermitAllProcessAccessPolicy, scope)
|
||||
createConsoleModule(PermitAllConsoleAccessPolicy, scope)
|
||||
createHttpModule(PermitAllHttpAccessPolicy, scope)
|
||||
createNetModule(PermitAllNetAccessPolicy, scope)
|
||||
createWsModule(PermitAllWsAccessPolicy, scope)
|
||||
|
||||
// Now scripts can import them
|
||||
session.eval("""
|
||||
import lyng.io.fs
|
||||
import lyng.io.process
|
||||
import lyng.io.console
|
||||
import lyng.io.http
|
||||
import lyng.io.net
|
||||
import lyng.io.ws
|
||||
|
||||
println("Working dir: " + Path(".").readUtf8())
|
||||
println("OS: " + Platform.details().name)
|
||||
println("TTY: " + Console.isTty())
|
||||
println("HTTP available: " + Http.isSupported())
|
||||
println("TCP available: " + Net.isTcpAvailable())
|
||||
println("WS available: " + Ws.isSupported())
|
||||
""")
|
||||
}
|
||||
```
|
||||
@@ -76,21 +94,27 @@ suspend fun runMyScript() {
|
||||
- **Filesystem Security:** Implement `FsAccessPolicy` to restrict access to specific paths or operations (e.g., read-only access to a sandbox directory).
|
||||
- **Process Security:** Implement `ProcessAccessPolicy` to restrict which executables can be run or to disable shell execution entirely.
|
||||
- **Console Security:** Implement `ConsoleAccessPolicy` to control output writes, event reads, and raw mode switching.
|
||||
- **HTTP Security:** Implement `HttpAccessPolicy` to restrict which requests scripts may send.
|
||||
- **Transport Security:** Implement `NetAccessPolicy` to restrict DNS resolution and TCP/UDP socket operations.
|
||||
- **WebSocket Security:** Implement `WsAccessPolicy` to restrict websocket connects and message flow.
|
||||
|
||||
For more details, see the specific module documentation:
|
||||
- [Filesystem Security Details](lyng.io.fs.md#access-policy-security)
|
||||
- [Process Security Details](lyng.io.process.md#security-policy)
|
||||
- [Console Module Details](lyng.io.console.md)
|
||||
- [HTTP Module Details](lyng.io.http.md)
|
||||
- [Transport Networking Details](lyng.io.net.md)
|
||||
- [WebSocket Module Details](lyng.io.ws.md)
|
||||
|
||||
---
|
||||
|
||||
#### Platform Support Overview
|
||||
|
||||
| Platform | lyng.io.fs | lyng.io.process | lyng.io.console |
|
||||
| :--- | :---: | :---: | :---: |
|
||||
| **JVM** | ✅ | ✅ | ✅ (baseline) |
|
||||
| **Native (Linux/macOS)** | ✅ | ✅ | 🚧 |
|
||||
| **Native (Windows)** | ✅ | 🚧 (Planned) | 🚧 |
|
||||
| **Android** | ✅ | ❌ | ❌ |
|
||||
| **NodeJS** | ✅ | ❌ | ❌ |
|
||||
| **Browser / Wasm** | ✅ (In-memory) | ❌ | ❌ |
|
||||
| Platform | lyng.io.fs | lyng.io.process | lyng.io.console | lyng.io.http | lyng.io.ws | lyng.io.net |
|
||||
| :--- | :---: | :---: | :---: | :---: | :---: | :---: |
|
||||
| **JVM** | ✅ | ✅ | ✅ (baseline) | ✅ | ✅ | ✅ |
|
||||
| **Native (Linux/macOS)** | ✅ | ✅ | 🚧 | 🚧 | 🚧 | 🚧 |
|
||||
| **Native (Windows)** | ✅ | 🚧 (Planned) | 🚧 | 🚧 | 🚧 | 🚧 |
|
||||
| **Android** | ✅ | ❌ | ❌ | 🚧 | 🚧 | 🚧 |
|
||||
| **NodeJS** | ✅ | ❌ | ❌ | 🚧 | 🚧 | 🚧 |
|
||||
| **Browser / Wasm** | ✅ (In-memory) | ❌ | ❌ | 🚧 | 🚧 | 🚧 |
|
||||
Reference in new issue
Block a user