nervur 0.14.0 → 0.16.0
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/LICENSE +2 -1
- package/NOTICE +5 -1
- package/README.md +23 -448
- package/index.js +17 -0
- package/nervur.js +5 -0
- package/package.json +32 -15
- package/GETTING-STARTED.md +0 -111
- package/SECURITY.md +0 -11
- package/admin.mjs +0 -83
- package/being.mjs +0 -639
- package/blueprint.mjs +0 -512
- package/client.mjs +0 -70
- package/contract.mjs +0 -98
- package/ground.mjs +0 -382
- package/index.mjs +0 -20
- package/modules.mjs +0 -55
- package/pointer.mjs +0 -79
- package/program.mjs +0 -119
- package/tools.mjs +0 -162
- package/voice.mjs +0 -107
package/GETTING-STARTED.md
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
# Getting started — two castles
|
|
2
|
-
|
|
3
|
-
Picture a castle: one gate, its own residents, its own law. A **ground** is
|
|
4
|
-
the castle — one sovereign process, one handler where every letter arrives.
|
|
5
|
-
Its residents are **beings**; its capabilities are **modules**; the ground
|
|
6
|
-
under it is a **floor** — a filesystem, or a browser's IndexedDB — and the
|
|
7
|
-
stance it takes toward the world is its **terrain**. This page raises two
|
|
8
|
-
castles on two terrains and has them speak: a **mountain** (a server, always
|
|
9
|
-
reachable, always remembering) and a **house of cards** (a browser tab,
|
|
10
|
-
raised in seconds, holding what it can afford to lose). Same castle, same
|
|
11
|
-
law, different ground under it.
|
|
12
|
-
|
|
13
|
-
Everything below runs today — the bench drives this exact story in
|
|
14
|
-
`bench/worlds/story/`.
|
|
15
|
-
|
|
16
|
-
## The mountain
|
|
17
|
-
|
|
18
|
-
The machine's raise is one config and one daemon —
|
|
19
|
-
[`nervurd`](https://www.npmjs.com/package/nervurd) is the host, and its
|
|
20
|
-
README is the operator's full page. The five-minute shape:
|
|
21
|
-
|
|
22
|
-
```sh
|
|
23
|
-
npm install -g nervurd
|
|
24
|
-
nervur self mint --self ./hand.json --heir ./heir.json
|
|
25
|
-
nervur init --config ./castle.json --self ./hand.json
|
|
26
|
-
NERVUR_SECRET=... nervurd --config ./castle.json
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
The config names the shelf, the door, the secret's environment variable,
|
|
30
|
-
and the modules — the castle's capabilities, chosen by you:
|
|
31
|
-
|
|
32
|
-
```json
|
|
33
|
-
{
|
|
34
|
-
"cells": "/var/lib/nervur/castle.json",
|
|
35
|
-
"listen": { "host": "127.0.0.1", "port": 7001 },
|
|
36
|
-
"secret": "NERVUR_SECRET",
|
|
37
|
-
"modules": {}
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Keep the heir off the machine. Whoever takes the machine takes what the
|
|
42
|
-
castle holds today; the heir is why they can never become it tomorrow.
|
|
43
|
-
|
|
44
|
-
## The house of cards
|
|
45
|
-
|
|
46
|
-
The browser's raise is two calls from
|
|
47
|
-
[`@nervur-org/floor-web`](https://www.npmjs.com/package/@nervur-org/floor-web),
|
|
48
|
-
because a tab closes constantly and the two acts must not blur:
|
|
49
|
-
|
|
50
|
-
```js
|
|
51
|
-
import { found, wake } from '@nervur-org/floor-web';
|
|
52
|
-
|
|
53
|
-
// Once, ever: mint the identity, stand the castle, get custody back.
|
|
54
|
-
let kept;
|
|
55
|
-
const castle = found({ keep: (dump) => (kept = dump) });
|
|
56
|
-
// castle.address — the name; castle.custody — the hand, the heir, the
|
|
57
|
-
// secret: yours to keep (IndexedDB, or a mountain you trust), never the
|
|
58
|
-
// ground's.
|
|
59
|
-
|
|
60
|
-
// Every session after: same name, same residents, no identity act.
|
|
61
|
-
// wake hands back the standing ground itself — woken.address is the name.
|
|
62
|
-
const woken = wake({ held: kept, secret: castle.custody.secret });
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
Where `kept` and `custody` live is your choice, under this terrain's honest
|
|
66
|
-
limit: a browser may evict what it keeps — a card castle holds what it can
|
|
67
|
-
afford to lose, and keeps what is precious in its relationship with a
|
|
68
|
-
mountain.
|
|
69
|
-
|
|
70
|
-
## They speak
|
|
71
|
-
|
|
72
|
-
A letter is a letter on every terrain: one signed envelope, carried
|
|
73
|
-
however the two castles can reach each other — here, `fetch` to the
|
|
74
|
-
mountain's door. First the mountain's keeper invites the card castle's
|
|
75
|
-
founder (one signed act at the admin door — the CLI, or any client the
|
|
76
|
-
keeper holds), and then the founder asks from the browser:
|
|
77
|
-
|
|
78
|
-
```js
|
|
79
|
-
import { Client, Tools, Voice } from 'nervur';
|
|
80
|
-
|
|
81
|
-
const me = Voice.revive(castle.custody.hand);
|
|
82
|
-
const talk = Client({
|
|
83
|
-
voice: me,
|
|
84
|
-
deliver: async (envelope) => {
|
|
85
|
-
const res = await fetch('http://127.0.0.1:7001', {
|
|
86
|
-
body: JSON.stringify(envelope),
|
|
87
|
-
headers: { 'content-type': 'application/json' },
|
|
88
|
-
method: 'POST',
|
|
89
|
-
});
|
|
90
|
-
return res.status === 200 ? res.json() : undefined;
|
|
91
|
-
},
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
const heard = await talk.ask(mountainAddress, '{ census { active } }');
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
The client verifies every answer from the address alone — the mountain's
|
|
98
|
-
word arrives signed, and a broken or missing signature is dropped exactly
|
|
99
|
-
like silence. A stranger who was never invited gets silence too, and cannot
|
|
100
|
-
tell refusal from absence. That is the whole protocol: **say who you are,
|
|
101
|
-
name whom you seek, and the castle answers or keeps quiet.**
|
|
102
|
-
|
|
103
|
-
## Where to go next
|
|
104
|
-
|
|
105
|
-
- [`nervur`'s README](README.md) — the library underneath both castles.
|
|
106
|
-
- [`nervurd`'s README](../nervurd/README.md) — the operator's page: checks,
|
|
107
|
-
rotation, backups, the door's full behaviour.
|
|
108
|
-
- [`@nervur-org/floor-web`](../floor-web/README.md) — the web floor's
|
|
109
|
-
terrain contract, founding and waking in full.
|
|
110
|
-
- [`@nervur-org/species`](../species/README.md) — blueprints your castles
|
|
111
|
-
grow beings from.
|
package/SECURITY.md
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
# Security
|
|
2
|
-
|
|
3
|
-
This package answers one question — by whose authority — and a hole in that
|
|
4
|
-
answer is the most serious bug it can have.
|
|
5
|
-
|
|
6
|
-
Report vulnerabilities privately to **<security@nervur.com>**. Do not open a
|
|
7
|
-
public report. State what you ran, what you sent, and what answered; a
|
|
8
|
-
proof of concept is welcome but not required.
|
|
9
|
-
|
|
10
|
-
A person reads every report. Fixes ship as releases on the live 0.x line,
|
|
11
|
-
and the report is credited if you want it to be.
|
package/admin.mjs
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
const ADMIN = `({
|
|
2
|
-
name: 'nervur.ground',
|
|
3
|
-
needs: { modules: [{ module: 'memory', contract: 'nervur.memory' }] },
|
|
4
|
-
memory: {
|
|
5
|
-
'aliases/*': { type: 'String', class: 'data' },
|
|
6
|
-
wears: { type: 'String', class: 'data' },
|
|
7
|
-
},
|
|
8
|
-
interface: \`
|
|
9
|
-
input RefInput { address: String!, nextPkHash: String, rights: String }
|
|
10
|
-
type Resident { address: String!, alias: String, digest: String, active: Boolean! }
|
|
11
|
-
type Census { residents: [Resident!]!, stored: Int!, active: Int! }
|
|
12
|
-
type Query {
|
|
13
|
-
census: Census @rights(is: [SELF, MEMBER])
|
|
14
|
-
aliasOf(name: String!): String @rights(is: [SELF, MEMBER])
|
|
15
|
-
attest(module: String!): Boolean @rights(is: [SELF, MEMBER])
|
|
16
|
-
opened: Boolean @rights(is: [SELF, MEMBER, STRANGER])
|
|
17
|
-
wears: String @rights(is: [SELF, MEMBER, STRANGER])
|
|
18
|
-
}
|
|
19
|
-
type Mutation {
|
|
20
|
-
invite(address: String!, nextPkHash: String, rights: String): Boolean @rights(is: [SELF, MEMBER])
|
|
21
|
-
drop(address: String!): Boolean @rights(is: [SELF, MEMBER])
|
|
22
|
-
extend(program: String): Boolean @rights(is: [SELF])
|
|
23
|
-
create(program: String!, refs: [RefInput!], data: String, config: String): String
|
|
24
|
-
@rights(is: [SELF, MEMBER])
|
|
25
|
-
activate(address: String!): String @rights(is: [SELF, MEMBER])
|
|
26
|
-
destroy(address: String!): String @rights(is: [SELF, MEMBER])
|
|
27
|
-
upgrade(address: String!, program: String!): Boolean @rights(is: [SELF, MEMBER])
|
|
28
|
-
alias(name: String!, address: String!): Boolean @rights(is: [SELF, MEMBER])
|
|
29
|
-
wear(address: String): Boolean @rights(is: [SELF, MEMBER])
|
|
30
|
-
}
|
|
31
|
-
\`,
|
|
32
|
-
resolvers: {
|
|
33
|
-
Query: {
|
|
34
|
-
census: (_, __, { registry }) => {
|
|
35
|
-
const residents = registry.residents();
|
|
36
|
-
return {
|
|
37
|
-
active: residents.filter((one) => one.active).length,
|
|
38
|
-
residents,
|
|
39
|
-
stored: residents.length,
|
|
40
|
-
};
|
|
41
|
-
},
|
|
42
|
-
aliasOf: (_, { name }, { modules }) => modules.memory.read('aliases/' + name),
|
|
43
|
-
attest: (_, { module }, { registry }) => registry.attest(module),
|
|
44
|
-
opened: (_, __, { modules }) => modules.memory.list('refs/').length > 0,
|
|
45
|
-
wears: (_, __, { modules }) => modules.memory.read('wears') ?? null,
|
|
46
|
-
},
|
|
47
|
-
Mutation: {
|
|
48
|
-
invite: (_, { address, nextPkHash, rights }, { modules }) =>
|
|
49
|
-
modules.memory.write('refs/' + address, {
|
|
50
|
-
nextPkHash: nextPkHash ?? null,
|
|
51
|
-
rights: rights ?? 'MEMBER',
|
|
52
|
-
}) !== undefined,
|
|
53
|
-
drop: (_, { address }, { modules }) => {
|
|
54
|
-
if (modules.memory.read('refs/' + address) === undefined) {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
modules.memory.write('refs/' + address, undefined);
|
|
58
|
-
return modules.memory.read('refs/' + address) === undefined;
|
|
59
|
-
},
|
|
60
|
-
extend: (_, { program }, { registry }) => registry.extend(program) !== undefined,
|
|
61
|
-
create: (_, { program, refs, data, config }, { registry }) =>
|
|
62
|
-
registry.create({
|
|
63
|
-
config: config === undefined ? undefined : JSON.parse(config),
|
|
64
|
-
data: data ? JSON.parse(data) : {},
|
|
65
|
-
program,
|
|
66
|
-
refs: refs ?? [],
|
|
67
|
-
}),
|
|
68
|
-
activate: (_, { address }, { registry }) =>
|
|
69
|
-
registry.activate(address) === undefined ? null : address,
|
|
70
|
-
destroy: (_, { address }, { registry }) => registry.destroy(address) ?? null,
|
|
71
|
-
upgrade: (_, { address, program }, { registry }) =>
|
|
72
|
-
registry.upgrade({ address, program }) !== undefined,
|
|
73
|
-
alias: (_, { name, address }, { modules }) =>
|
|
74
|
-
modules.memory.write('aliases/' + name, address) !== undefined,
|
|
75
|
-
wear: (_, { address }, { modules }) => {
|
|
76
|
-
modules.memory.write('wears', address ?? undefined);
|
|
77
|
-
return modules.memory.read('wears') === (address ?? undefined);
|
|
78
|
-
},
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
})`;
|
|
82
|
-
|
|
83
|
-
export { ADMIN };
|