Skip to content

Commit 156671d

Browse files
Scaffold + relay: the out-of-tree plugin experiment begins
Repo charter in README (public-api-only rule, findings-first), shared test harness (helpers.js), and the pattern-setting port: the NIP-01 relay via api.ws.route with pluginDir persistence core doesn't have. Findings in relay/README: ws.route sufficed; event verification is internal (vendored).
0 parents  commit 156671d

10 files changed

Lines changed: 3436 additions & 0 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules/
2+
*.log
3+
test-data-*/
4+
data/

LICENSE

Lines changed: 661 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# jss-plugins — the out-of-tree experiment
2+
3+
**Status: experimental.** Ports of [JavaScript Solid
4+
Server](https://github.com/JavaScriptSolidServer/JavaScriptSolidServer)'s
5+
bundled features onto the [#206 plugin
6+
loader](https://jss.live/docs/features/plugins) (`createServer({ plugins })`,
7+
JSS ≥ 0.0.215) — each living **outside** the JSS tree, using only what a real
8+
third-party plugin gets.
9+
10+
## Why
11+
12+
Inside `src/`, the bundled features cheat: they import internals, share
13+
closures with server.js, and reach around WAC. Out here a port can only use
14+
the public surface — `activate(api)` plus the documented imports — so:
15+
16+
- every port is an **honest test** of the plugin api,
17+
- every wall a port hits is a **seam discovery**, written up in
18+
[NOTES.md](./NOTES.md) before it becomes an upstream issue,
19+
- and core stays untouched: these are parallel implementations, not
20+
migrations. Nothing here removes or changes anything in JSS.
21+
22+
This is the plugin-zero method
23+
([#582](https://github.com/JavaScriptSolidServer/JavaScriptSolidServer/issues/582)
24+
[#584](https://github.com/JavaScriptSolidServer/JavaScriptSolidServer/issues/584)
25+
[#588](https://github.com/JavaScriptSolidServer/JavaScriptSolidServer/issues/588)
26+
[#589](https://github.com/JavaScriptSolidServer/JavaScriptSolidServer/pull/589))
27+
applied to JSS's own feature set.
28+
29+
## The rule
30+
31+
A plugin directory may import:
32+
33+
1. `javascript-solid-server/auth.js` (`getAgent`) — the documented contract,
34+
2. whatever the `activate(api)` surface provides,
35+
3. its own npm dependencies.
36+
37+
**Never `javascript-solid-server/src/...`.** If a port can't be written
38+
without internals, that gap is the finding — document it in the port's
39+
README and NOTES.md, ship the closest honest approximation.
40+
41+
## Layout
42+
43+
```
44+
relay/ NIP-01 nostr relay (port of src/nostr/relay.js)
45+
webrtc/ WebRTC signaling rooms (port of src/webrtc/index.js)
46+
terminal/ WebSocket shell — GATED (port of src/terminal/index.js)
47+
tunnel/ reverse tunnel over WebSocket (port of src/tunnel/)
48+
notifications/ pod change notifications (port of src/notifications/ — the seam-forcer)
49+
pay/ HTTP 402 paid routes (port of src/mrc20.js pay mode — wall-report)
50+
compose.test.js ONE server, every plugin, from pure config
51+
serve.js demo composition
52+
NOTES.md findings log: what the api gave us, what it didn't
53+
```
54+
55+
Each directory: `plugin.js` (exports `activate(api)`), `test.js` (boots a
56+
real JSS from npm), `README.md` (usage + findings for that port).
57+
58+
## Run
59+
60+
```bash
61+
npm install
62+
npm test # every port's tests + the all-plugins composition
63+
npm run serve # one server: pods + every plugin
64+
```
65+
66+
## License
67+
68+
AGPL-3.0-only, same as JSS — several ports adapt JSS source.

helpers.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Shared test harness: boot a real JavaScript Solid Server from npm with a
2+
// set of plugin entries, on a probed port, against a throwaway data root.
3+
//
4+
// createServer is the documented composition entry (docs/configuration.md);
5+
// the no-internals rule is about *plugins*, not the host the tests boot.
6+
7+
import fs from 'node:fs';
8+
import net from 'node:net';
9+
import os from 'node:os';
10+
import path from 'node:path';
11+
import { createServer } from 'javascript-solid-server/src/server.js';
12+
13+
function probePort() {
14+
return new Promise((resolve, reject) => {
15+
const probe = net.createServer();
16+
probe.once('error', reject);
17+
probe.listen(0, '127.0.0.1', () => {
18+
const port = probe.address().port;
19+
probe.close(() => resolve(port));
20+
});
21+
});
22+
}
23+
24+
/**
25+
* @param {object} opts extra createServer options (idp, …)
26+
* @param {Array} opts.plugins plugin entries under test
27+
* @returns {{ base, wsBase, root, fastify, close }}
28+
*/
29+
export async function startJss({ plugins, ...opts } = {}) {
30+
const root = opts.root ?? fs.mkdtempSync(path.join(os.tmpdir(), 'jss-plugins-test-'));
31+
delete opts.root;
32+
const port = await probePort();
33+
const fastify = createServer({
34+
logger: false,
35+
forceCloseConnections: true,
36+
root,
37+
...(opts.idp ? { idpIssuer: `http://127.0.0.1:${port}` } : {}),
38+
plugins,
39+
...opts,
40+
});
41+
await fastify.listen({ port, host: '127.0.0.1' });
42+
return {
43+
base: `http://127.0.0.1:${port}`,
44+
wsBase: `ws://127.0.0.1:${port}`,
45+
root,
46+
fastify,
47+
async close({ keepData = false } = {}) {
48+
await fastify.close();
49+
if (!keepData) fs.rmSync(root, { recursive: true, force: true });
50+
},
51+
};
52+
}
53+
54+
/** Collect messages from a ws until predicate or timeout. */
55+
export function wsCollect(socket, isDone, timeoutMs = 4000) {
56+
return new Promise((resolve, reject) => {
57+
const msgs = [];
58+
const timer = setTimeout(() => reject(new Error(`ws timeout; got ${JSON.stringify(msgs)}`)), timeoutMs);
59+
socket.on('message', (data) => {
60+
msgs.push(JSON.parse(String(data)));
61+
if (isDone(msgs)) {
62+
clearTimeout(timer);
63+
resolve(msgs);
64+
}
65+
});
66+
socket.on('error', (err) => {
67+
clearTimeout(timer);
68+
reject(err);
69+
});
70+
});
71+
}

0 commit comments

Comments
 (0)