Skip to content

Latest commit

 

History

8 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@cldmv/slothlet-vine

Vines between slothlet api trees.

npm version npm downloads GitHub downloads Last commit npm last update coverage

Contributors Sponsor shinrai


Slothlet composes a folder of modules into an api tree. A vine connects two trees across an execution boundary — a Web Worker, another thread, another process, or another machine — by mounting forwarding leaves: stubs that live at the callee's identical logical path in the caller's tree, so self.exts.foo.bar() works the same whether foo is co-located or isolated. Slothlet cannot tell a vine leaf from a real one — including its permission identity, so a rule targeting exts.foo.bar gates the forwarding stub exactly as it would gate the real leaf, before it dispatches.

That gating follows slothlet's own rule about who is calling: a call made by a MODULE (self.exts.foo.bar()) is checked against the permission rules, and a denied one never runs the stub body, so it never reaches the wire. A call made through the bound handle slothlet() returned — the host itself — carries host standing and is not checked. That carve-out is slothlet's design, not a vine gap, but it does mean "permission-gated" describes module-initiated calls; a host that forwards on someone else's behalf is responsible for its own authorization.


✨ What's New

Latest: v1.1.2 (September 2026)

  • @cldmv/slothlet peer floor raised to >=3.20.0 (#31) — the suite now runs against slothlet 3.20.0, so that is the version the peer range guarantees. No runtime source changed; the rest of the release is dev-tooling bumps.
  • View full v1.1.2 Changelog

Recent Releases

  • v1.1.1 (September 2026) — CI-only: release-flow caller workflows synced to the current v4 templates (Changelog)
  • v1.1.0 (September 2026) — cross-vine event forwarding in both directions, gated by the emitter's own permissions (Changelog)
  • v1.0.2 (September 2026) — dev-only: @cldmv/slothlet dev pin 3.15.0 → 3.15.1 (peer floor unchanged) (Changelog)
  • v1.0.1 (August 2026) — dev-only: eslint 10.9.0 → 10.9.1 (Changelog)

📚 For complete version history and detailed release notes, see the docs/changelog/ folder.


🚀 Key Features

🎯 Location-Transparent Forwarding

grow() mounts one stub per far-side leaf at the identical dotted path slothlet would use locally — self.exts.pdfViewer.open() reads the same whether pdfViewer runs in-process, in a worker, or in another machine entirely.

🔐 Permission-Gated by Slothlet Itself

A mounted stub is a real slothlet leaf as far as slothlet's own permission system is concerned. There is no separate vine-side authorization layer to configure, audit, or drift out of sync with the rest of the api tree.

📦 Data-Only by Design

A function argument or return value is refused at the edge with a named, catchable error — never a silent clone-crash, and never a live closure smuggled across an isolation boundary.

🔌 Five Built-In Transports, Pluggable Contract

loopback, post-message, worker-threads, process, and websocket ship as independent subpath exports (only what you import is pulled in). Anything that can implement the small Channel interface — send, onMessage, close, an optional onClose, and a capabilities declaration — can host a vine.

⏱ Settle-Once Correlation & Budgets

Every call is correlated by callId and bounded by a per-call budget. A pending call always settles — success, error, or timeout — even against a far side that never answers.

🧪 Reusable Conformance Harness

@cldmv/slothlet-vine/testing exports the same framework-injected test suite the five built-in transports are held to, so a custom transport can be verified against the identical contract.

🛡 100% Test Coverage

Statements, branches, functions, and lines — held to the same bar as slothlet itself.


📦 Installation

Requirements

  • A slothlet instance to grow from or serve — @cldmv/slothlet >=3.14.0 (peer dependency)
  • ESM (import); CommonJS interop follows whatever your bundler/runtime provides for a "type": "module" package
  • The websocket transport additionally needs the optional peer ws >=8.0.0 — only if you import it

Install

npm install @cldmv/slothlet-vine

🚀 Quick Start

import * as vine from "@cldmv/slothlet-vine";
import { createPair } from "@cldmv/slothlet-vine/transport/loopback";

const [near, far] = createPair();

// serve this instance's leaves to the far side
const serving = await vine.serve(workerApi, far, { paths: ["exts"] });

// mount the far tree's leaves into this instance, at identical paths
const link = await vine.grow(hostApi, near, { budgetMs: 5000 });
await hostApi.exts.pdfViewer.open("a.pdf"); // executes on the serving instance

await link.close(); // stubs unmounted; in-flight calls settle VINE_CLOSED
serving.close();

Swap transport/loopback for any of the other four built-in transports, or your own Channel implementation, without changing anything above createPair()/connect(). With a real boundary, create the channel in the same tick as the worker, child or socket it wraps — before any await — so the far side's one-shot surface frame always has a listener to land on; after that, the transport queues it until grow() is ready (see Transports → Create the channel before you await anything). Single-word leaves, context carried by the namespace — never growVine()-style camelCase that repeats the package's own name.


📚 Configuration

grow() and serve() both take (api, channel, options) — the local slothlet instance, the transport seam, and an options object. The complete reference — every option, every return field — lives in docs/CONFIGURATION.md.

Function Option Type Default Description
serve() paths string[] every callable leaf Dotted prefixes to publish
serve() modules string[] — Extra moduleIDs to union in (runtime add() mounts leaves() can't see)
grow() budgetMs number 30000 Per-call settle budget; exceeded → VINE_BUDGET
grow() handshakeMs number budgetMs Deadline for the initial surface (leaf-manifest) frame
grow() paths string[] every published leaf Dotted prefixes to mount (grow-side mirror of serve()'s own filter)

serving.close()/link.close() never close the channel itself — a channel may outlive one grow/serve pairing, and one a consumer handed in is not this call's to tear down.


📚 Documentation

docs/ isn't included in the published npm package (only src, schemas, README.md, and LICENSE ship — see DESIGN.md), so every link below is absolute and works the same from npmjs.com, an editor previewing the installed package, or GitHub itself.

Reference

  • Design & Protocol — the normative Channel contract, frame schema, grow/serve semantics, and error taxonomy. If a guide below and this disagree, this wins.
  • Configuration Reference — every grow()/serve() option, with defaults, and what link/serving return.
  • Changelog — all release notes.

Technical Guides

  • Transports — the five built-in transports, when to reach for each, and the death-detection/ownership details that differ between them.
  • Writing a Custom Transport — implementing the Channel contract, the uniform send-failure policy, and verifying it with the shared conformance harness.
  • Error Reference — the VINE_* code list, VineError/VineRemoteError, and why a remote VINE_* code is never adopted as-is.
  • Permissions — how slothlet's own permission system gates a mounted stub exactly like a real leaf.
  • Using a Vine in the Browser — a full Web Worker walkthrough with the post-message transport.

CodeFactor npms.io score npm unpacked size Repo size


🔗 Links


📄 License

GitHub license npm license

Apache-2.0 © Shinrai / CLDMV

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages