nervur 0.22.2-7 → 0.23.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/AUTHORING.md +87 -57
- package/COMMAND.md +73 -22
- package/FACES.md +22 -17
- package/FACULTIES.md +50 -30
- package/GROUNDS.md +185 -82
- package/README.md +8 -8
- package/dist/bench/bench-ground.d.ts +6 -6
- package/dist/bench/bench-ground.js +55 -27
- package/dist/browser/browser-ground.d.ts +4 -4
- package/dist/browser/browser-ground.js +95 -31
- package/dist/edge/edge-ground.d.ts +5 -5
- package/dist/edge/edge-ground.js +85 -61
- package/dist/edge/secret-unlock.d.ts +1 -1
- package/dist/edge/secret-unlock.js +1 -1
- package/dist/ground/dock.d.ts +1460 -0
- package/dist/ground/dock.js +1159 -0
- package/dist/ground/ground.d.ts +138 -235
- package/dist/ground/ground.js +610 -661
- package/dist/ground/views.d.ts +17 -0
- package/dist/ground/views.js +20 -0
- package/dist/house/crossing.d.ts +3 -2
- package/dist/house/crossing.js +5 -4
- package/dist/house/house.d.ts +11 -1
- package/dist/house/house.js +104 -26
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/node/bridge.d.ts +3 -3
- package/dist/node/bridge.js +2 -2
- package/dist/node/cli.js +63 -31
- package/dist/node/hand.d.ts +4 -3
- package/dist/node/hand.js +3 -3
- package/dist/node/node-ground.d.ts +6 -7
- package/dist/node/node-ground.js +167 -101
- package/dist/node/shell.d.ts +11 -0
- package/dist/node/shell.js +35 -0
- package/dist/node/tcp-carry.d.ts +4 -2
- package/dist/node/tcp-carry.js +14 -5
- package/package.json +2 -1
package/FACULTIES.md
CHANGED
|
@@ -15,14 +15,22 @@ the package's own tests run.
|
|
|
15
15
|
## What a faculty owes
|
|
16
16
|
|
|
17
17
|
A faculty answers a blueprint: a name, and methods with their schemas.
|
|
18
|
-
A
|
|
18
|
+
A registry holds it by name as `{ takes?, up, install? }`. The ground
|
|
19
|
+
raises it by its `up` into a body, and hands the body to its houses as
|
|
19
20
|
an offer, with the kinds its entry grants.
|
|
20
21
|
|
|
21
22
|
```text
|
|
22
|
-
faculty = {
|
|
23
|
+
faculty = { takes?, install?, up }
|
|
24
|
+
takes = { args?: schema, secrets?: { [name]: what it holds } }
|
|
25
|
+
body = { blueprint?, object?, window?, handler?, registry?, down? }
|
|
23
26
|
offer = { blueprint, object, kinds?, window? }
|
|
24
27
|
```
|
|
25
28
|
|
|
29
|
+
- **It declares what it takes.** `takes.args` is a schema built with
|
|
30
|
+
`s` from `nervur/being`, which its entry's args meet. `takes.secrets`
|
|
31
|
+
names each secret its entry must name, with a line saying what it
|
|
32
|
+
holds. The hand refuses an entry that fails either, before it lands,
|
|
33
|
+
and `facultiesCatalog` shows it to whoever writes the entry.
|
|
26
34
|
- **The object has the blueprint's methods.** Each takes one args object
|
|
27
35
|
and a context, and answers `{ result }` or `{ error: { message } }`.
|
|
28
36
|
- **An error is final, and a throw is not.** An error reaches the being
|
|
@@ -45,7 +53,7 @@ answered, with the same call id every time.
|
|
|
45
53
|
So one call arrives more than once. A reply lost on its way back brings
|
|
46
54
|
it again, and so does a program that died before it answered. A faculty
|
|
47
55
|
that changes the world keeps each call id with the answer it gave, in
|
|
48
|
-
the memory its
|
|
56
|
+
the memory its `up` receives, where a restart and a move keep it. It
|
|
49
57
|
answers a call id it has seen with that answer, and acts once.
|
|
50
58
|
|
|
51
59
|
It keeps them for its `window`, seven days where the offer names none.
|
|
@@ -84,31 +92,43 @@ reaches her through a standing, so policy is written as a being.
|
|
|
84
92
|
|
|
85
93
|
### It lives in the ground
|
|
86
94
|
|
|
87
|
-
The object arrives living. The ground
|
|
88
|
-
name, awaiting its
|
|
89
|
-
it. Every being whose need it covers holds the same object.
|
|
90
|
-
receives
|
|
95
|
+
The object arrives living. The ground raises each faculty its entries
|
|
96
|
+
name, awaiting its `up`, and the house never starts, stops or restarts
|
|
97
|
+
it. Every being whose need it covers holds the same object. Its `up`
|
|
98
|
+
receives four things beside the faculty's name.
|
|
91
99
|
|
|
92
100
|
- **`args`** are its entry's, as the owner wrote them.
|
|
93
101
|
- **`secrets`** are the secrets its entry names, set through the hand
|
|
94
|
-
and kept sealed in the ground's
|
|
102
|
+
and kept sealed in a being of the ground's dock. No other code reads
|
|
103
|
+
them.
|
|
95
104
|
- **`memory`** is the faculty's own, a view of the ground's memory
|
|
96
105
|
sealed under a key the ground derives for it. Its call ids live there,
|
|
97
106
|
so they move with the ground.
|
|
107
|
+
- **`faculties`** holds the object of each body its entry names in
|
|
108
|
+
`faculties`, so one body calls another directly. It goes up after
|
|
109
|
+
each of them.
|
|
98
110
|
|
|
99
|
-
|
|
100
|
-
|
|
111
|
+
`install` receives the same, and does the slow work once for each entry.
|
|
112
|
+
A program's packages and a repository's checkout are installed there, so
|
|
113
|
+
going up again installs nothing.
|
|
114
|
+
|
|
115
|
+
A body answers four things beside its methods, each where it has one.
|
|
101
116
|
|
|
102
117
|
- **`handler`** answers HTTP on the ground's one listener. It takes a
|
|
103
118
|
`Request` and answers a `Response`, or `null` where the request is not
|
|
104
|
-
its own. A site, an API or an MCP server is a
|
|
105
|
-
- **`
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
119
|
+
its own. A site, an API or an MCP server is a body with a handler.
|
|
120
|
+
- **`down`** lets go of what its `up` opened. The ground calls it when
|
|
121
|
+
the body is updated, restarted or removed, and when the ground stops,
|
|
122
|
+
bodies in the reverse of the order they stood.
|
|
123
|
+
- **`registry`** holds more faculties, for every entry that names this
|
|
124
|
+
body in `from`. A module of code, a git repository and a program's
|
|
125
|
+
catalogue are each a registry.
|
|
110
126
|
- **`window`** is how long it remembers a call id.
|
|
111
127
|
|
|
128
|
+
The hand changes a body. `faculties update` lands a new entry, and the
|
|
129
|
+
body goes down and up on it. `faculties restart` takes it down and up on
|
|
130
|
+
the same entry. Each house that names it opens again.
|
|
131
|
+
|
|
112
132
|
## Three ways to wrap a program
|
|
113
133
|
|
|
114
134
|
| Way | What the object is | What a crash takes |
|
|
@@ -120,7 +140,7 @@ one.
|
|
|
120
140
|
## The bridge
|
|
121
141
|
|
|
122
142
|
`bridge({ command, args, env, cwd, memory })` from `nervur/node` starts
|
|
123
|
-
a program and answers a
|
|
143
|
+
a program and answers a body. A NodeGround raises one by its faculty
|
|
124
144
|
`bridge`, from its entry alone. The program may be written in any
|
|
125
145
|
language. It speaks one JSON value a line on its standard streams.
|
|
126
146
|
|
|
@@ -143,7 +163,7 @@ in { id, result } | { id, error } the ground's answer to that
|
|
|
143
163
|
the same every time that call is sent, in every life of the program.
|
|
144
164
|
A handle called with no `call` is refused.
|
|
145
165
|
- **It starts with an empty environment.** It holds only what `env`
|
|
146
|
-
names, so it never reads the ground's key. The
|
|
166
|
+
names, so it never reads the ground's key. The faculty `bridge` names
|
|
147
167
|
there the secrets of its entry, each under its name.
|
|
148
168
|
- **It keeps its state in the faculty's memory.** A memory line names
|
|
149
169
|
`read`, `list` or `write` and the memory's args, every entry's bytes
|
|
@@ -365,22 +385,22 @@ it later, once.
|
|
|
365
385
|
|
|
366
386
|
The Pi's folder holds the program and a folder of classes for its
|
|
367
387
|
house, and no code of the ground's. The relay stands from its entry,
|
|
368
|
-
|
|
369
|
-
class alone.
|
|
388
|
+
raised by the faculty `bridge` of the NodeGround's folder, and granted
|
|
389
|
+
to the twin's class alone.
|
|
370
390
|
|
|
371
391
|
```bash
|
|
372
|
-
npx nervur faculties add name=relay make=bridge args='{"command":"python3","args":["relay.py"]}' kinds='["org.example.garage"]'
|
|
392
|
+
npx nervur faculties add name=relay from=folder make=bridge args='{"command":"python3","args":["relay.py"]}' kinds='["org.example.garage"]'
|
|
373
393
|
```
|
|
374
394
|
|
|
375
395
|
The house is added once, and names the relay among the faculties it
|
|
376
396
|
receives.
|
|
377
397
|
|
|
378
398
|
```bash
|
|
379
|
-
npx nervur houses add name=garage classes='{"
|
|
399
|
+
npx nervur houses add name=garage classes='{"faculty":"folder","at":"classes"}' faculties='["relay"]'
|
|
380
400
|
```
|
|
381
401
|
|
|
382
|
-
Both entries rest sealed
|
|
383
|
-
the relay again at every start.
|
|
402
|
+
Both entries rest sealed as cells of the ground's dock, so the ground
|
|
403
|
+
stands the relay again at every start.
|
|
384
404
|
|
|
385
405
|
## In JavaScript
|
|
386
406
|
|
|
@@ -423,16 +443,16 @@ serve(Doorbell, {
|
|
|
423
443
|
});
|
|
424
444
|
```
|
|
425
445
|
|
|
426
|
-
Its entry
|
|
427
|
-
args `["doorbell.js"]`. A faculty that needs no process of its own
|
|
428
|
-
plain object
|
|
446
|
+
Its entry raises it with the faculty `bridge`, its command `node` and
|
|
447
|
+
its args `["doorbell.js"]`. A faculty that needs no process of its own
|
|
448
|
+
is a plain object its `up` answers instead, as the shop's payments
|
|
429
449
|
are in [Writing for nervur](AUTHORING.md).
|
|
430
450
|
|
|
431
451
|
## Testing a faculty
|
|
432
452
|
|
|
433
453
|
A faculty is tested on BenchGround, the ground in memory from
|
|
434
454
|
`nervur/bench`, with the program itself behind the bridge. The test
|
|
435
|
-
hands the bench a registry whose
|
|
455
|
+
hands the bench a registry whose `bridge` faculty bridges the program, as a
|
|
436
456
|
NodeGround's own does, and stands the relay through the ground's hand,
|
|
437
457
|
as an owner does. A `FakeNetwork` joins
|
|
438
458
|
grounds and loses what the test tells it to lose, and its one clock
|
|
@@ -476,11 +496,11 @@ test('Each tap on the phone pulses the relay once, whatever fails between', { ti
|
|
|
476
496
|
host: 'pi',
|
|
477
497
|
names: ['garage.local'],
|
|
478
498
|
modules: { pi },
|
|
479
|
-
registry: { faculties: { bridge: ({ memory }) => bridge({ command: 'python3', args: [relay], cwd: pin, memory }) } },
|
|
499
|
+
registry: { faculties: { bridge: { up: ({ memory }) => bridge({ command: 'python3', args: [relay], cwd: pin, memory }) } } },
|
|
480
500
|
});
|
|
481
501
|
t.after(() => garage.down());
|
|
482
502
|
// The relay, granted to the twin's class alone.
|
|
483
|
-
await garage.hand({
|
|
503
|
+
await garage.hand({ method: 'facultiesAdd', args: { name: 'relay', make: 'bridge', kinds: ['org.example.garage'] } });
|
|
484
504
|
await garage.add('garage', 'pi', { faculties: ['relay'] });
|
|
485
505
|
await garage.ask({ house: 'garage', method: 'bear', args: { kind: 'org.example.garage', id: 'door' } });
|
|
486
506
|
|
package/GROUNDS.md
CHANGED
|
@@ -14,47 +14,95 @@ kept by what the ground stands on: a file, a keychain, a Worker's
|
|
|
14
14
|
secret. The part of a ground that answers it is its unlock. Everything
|
|
15
15
|
else the ground keeps is sealed under that key.
|
|
16
16
|
|
|
17
|
-
**It
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
17
|
+
**It unpacks in layers, each a faculty.** Every faculty has one
|
|
18
|
+
lifecycle. A registry holds faculties by name, each an object `{ takes?,
|
|
19
|
+
up, install? }`. Standing one raises it by its `up` into a body, the
|
|
20
|
+
living instance houses and other bodies use. `install` does the slow
|
|
21
|
+
work once for each entry, and a body's `down` lets go of what its `up`
|
|
22
|
+
opened.
|
|
23
|
+
|
|
24
|
+
| Layer | Its faculties | What they are |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| primordial | the memory, the unlock, crypto, tools, the clock | the host's, read from the environment alone |
|
|
27
|
+
| the ground's work | `ground` | the library's, offered to the dock alone |
|
|
28
|
+
| the dock | a house of the library's beings | the drawer, and the hand's one road |
|
|
29
|
+
| the ladder | the terrain's defaults and your entries | carries, code, and every custom faculty |
|
|
30
|
+
| the hand | a socket, a key, a channel | the owner's reach, up last and down first |
|
|
31
|
+
|
|
32
|
+
**It keeps its drawer as cells of the dock's beings.** The dock is a
|
|
33
|
+
house every ground stands, and its beings are the library's. A twin
|
|
34
|
+
stands for each faculty entry, a being for each house, and one for each
|
|
35
|
+
secret. Their cells hold every entry, what each faculty installed, each
|
|
36
|
+
house's seed and ward, every secret, and the ground's bound on every
|
|
37
|
+
ask. No row of the ground's stands beside them.
|
|
38
|
+
|
|
39
|
+
**Every name an entry gives is a standing.** A house's code, its memory
|
|
40
|
+
and the faculties it uses, and a faculty's registry, its callees and its
|
|
41
|
+
secrets, are relations between those beings. The dock's steward
|
|
42
|
+
introduces each, and her notes name the grant. An entry that names a
|
|
43
|
+
faculty or a secret the dock does not hold is refused, and nothing
|
|
44
|
+
lands.
|
|
45
|
+
|
|
46
|
+
**Its houses keep their places in the same memory.** The dock, each
|
|
47
|
+
house and each faculty sees a view of the ground's memory under a prefix
|
|
48
|
+
of its own. A house seals its own rows, and the ground seals each
|
|
49
|
+
faculty's. So what rests on the disk is ciphertext, and copying the key,
|
|
50
|
+
the memory and the code moves the whole ground. A memory the key opens
|
|
51
|
+
no dock in is refused.
|
|
52
|
+
|
|
53
|
+
**It stands its bodies on a ladder.** The ground's own registry is its
|
|
54
|
+
terrain's. A body may carry a registry of its own, and the faculties an
|
|
55
|
+
entry raises `from` it stand after it. A body stands after each body its
|
|
56
|
+
entry names in `faculties`, whose objects its `up` receives. A body that
|
|
57
|
+
fails to stand stays down and says why, and the ground boots beside it.
|
|
58
|
+
|
|
59
|
+
**Its terrain names default entries, and yours win.** Each ground stands
|
|
60
|
+
its carries and its bodies of code from entries of its own. Its one
|
|
61
|
+
clock is primordial, which the dock and every house receive.
|
|
62
|
+
An entry you land under the same name stands in its place.
|
|
34
63
|
|
|
35
64
|
```text
|
|
36
|
-
recipe { make: 'module', args: { at: 'recipe.ts' } }
|
|
65
|
+
recipe { from: 'folder', make: 'module', args: { at: 'recipe.ts' } }
|
|
37
66
|
payments { from: 'recipe', make: 'payments', secrets: ['stripe-key'], kinds: ['com.acme.order'] }
|
|
38
67
|
```
|
|
39
68
|
|
|
40
|
-
**It opens each house on its entry.** An entry names the body
|
|
41
|
-
house's code, the custom faculties it may use, and the
|
|
42
|
-
its asks may run. It names a body
|
|
43
|
-
its places apart from the ground's memory.
|
|
69
|
+
**It opens each house on its entry.** An entry names the body that
|
|
70
|
+
serves the house's code, the custom faculties it may use, and the
|
|
71
|
+
longest any of its asks may run. It names a body serving memory only
|
|
72
|
+
where the house keeps its places apart from the ground's memory. Beside
|
|
73
|
+
each body's name, it holds the args that body hands this house.
|
|
44
74
|
|
|
45
75
|
```text
|
|
46
|
-
shop { classes: {
|
|
76
|
+
shop { classes: { faculty: 'folder', at: 'shop' }, faculties: ['payments'], wait: 60000 }
|
|
47
77
|
```
|
|
48
78
|
|
|
79
|
+
**A change answers what stands, and an error means nothing landed.**
|
|
80
|
+
Adding or updating a faculty answers why its body is down, where it is.
|
|
81
|
+
Adding or updating a house answers its ward, or why it stays closed.
|
|
82
|
+
The entry lands either way, and the hand mends it later.
|
|
83
|
+
|
|
84
|
+
**It updates an entry in one write.** `update` lands the new entry over
|
|
85
|
+
the old. A house closes and opens again on it, as the same ward. A body
|
|
86
|
+
goes down, installs where its entry moved, and goes up, and each house
|
|
87
|
+
naming it opens again. `restart` takes a body down and up on its entry.
|
|
88
|
+
|
|
49
89
|
**It grants a faculty in two steps.** A house uses only the faculties its
|
|
50
90
|
entry names. Inside it, a being holds one only where the faculty's entry
|
|
51
|
-
names her class in `kinds`, or where it names none. So a raw
|
|
91
|
+
names her class in `kinds`, or where it names none. So a raw program
|
|
52
92
|
reaches one house and one class inside it.
|
|
53
93
|
|
|
54
|
-
**It hands each
|
|
55
|
-
and kept in
|
|
56
|
-
receives, and no other code reads one. The hand lists their names
|
|
57
|
-
never a value.
|
|
94
|
+
**It hands each faculty its secrets.** A secret is set through the hand
|
|
95
|
+
and kept in a being's cells. A faculty's entry names the secrets its
|
|
96
|
+
`up` receives, and no other code reads one. The hand lists their names
|
|
97
|
+
and the entries that name each, and never a value. A secret's cells are
|
|
98
|
+
shown to no one, and a changed secret reaches a body when it goes up
|
|
99
|
+
again.
|
|
100
|
+
|
|
101
|
+
**It holds each entry to what its faculty takes.** A faculty declares
|
|
102
|
+
`takes`: a schema its args meet, and the secrets its entry must name.
|
|
103
|
+
The hand refuses an entry that fails it, or that names a secret not
|
|
104
|
+
kept, and says what failed. `facultiesCatalog` shows every faculty the
|
|
105
|
+
ground can raise, and what each takes.
|
|
58
106
|
|
|
59
107
|
**It hooks every door and runs one listener.** Each house's door goes to
|
|
60
108
|
the ground's carry, which also delivers between the ground's own houses
|
|
@@ -62,36 +110,64 @@ without touching the network. Everything that speaks HTTP, Quo over the
|
|
|
62
110
|
web and every face, is a handler on one listener. A faculty stood while
|
|
63
111
|
the ground runs is served at once.
|
|
64
112
|
|
|
65
|
-
**
|
|
66
|
-
ground
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
113
|
+
**The dock's steward reaches the ground through two faculties.** The
|
|
114
|
+
`ground` faculty raises and lowers bodies, opens and closes houses,
|
|
115
|
+
shows the catalogue and moves a house's places. It is offered to the
|
|
116
|
+
dock's beings alone. The `shell` runs a command on the ground's machine,
|
|
117
|
+
where the terrain has one. The dock is offered it as any house is
|
|
118
|
+
offered a body. Its steward stands on the shell's twin, and the twin's
|
|
119
|
+
entry grants it to the dock's shell being alone. No entry names, makes
|
|
120
|
+
or grants either.
|
|
121
|
+
|
|
122
|
+
**A boot writes only what moved.** Each twin raises its body by a read,
|
|
123
|
+
and her cells are written only where what came of it differs. So a wake
|
|
124
|
+
that finds nothing changed writes nothing.
|
|
125
|
+
|
|
126
|
+
**It serves its owner's hand, and the hand has one road.** The hand
|
|
127
|
+
answers `describe`, and otherwise asks a being of the dock or of a house
|
|
128
|
+
as `root`. A request that names a house asks a being there. One that
|
|
129
|
+
names none asks the dock's steward. `describe` shows her asks, every
|
|
130
|
+
faculty with its methods or why it is down, and every house.
|
|
131
|
+
|
|
132
|
+
| The dock's asks | What they do | Who asks them |
|
|
70
133
|
| --- | --- | --- |
|
|
71
|
-
| `
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
74
|
-
| `
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
`
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
and
|
|
134
|
+
| `housesAdd`, `housesUpdate`, `housesRemove`, `housesList` | the houses | `root`, and a pilot |
|
|
135
|
+
| `facultiesAdd`, `facultiesUpdate`, `facultiesRestart`, `facultiesRemove`, `facultiesList` | the faculties | `root`, and a pilot |
|
|
136
|
+
| `facultiesCatalog` | every faculty the ground can raise, and what it takes | `root`, and a pilot |
|
|
137
|
+
| `waitSet`, `waitShow` | the ground's bound on every ask | `root`, and a pilot |
|
|
138
|
+
| `secretsSet`, `secretsRemove`, `secretsList` | the secrets | `root` alone |
|
|
139
|
+
| `movesOut`, `movesIn` | a house moved between grounds | `root` alone |
|
|
140
|
+
| `callFaculty` | a faculty's method, called by name | `root` alone |
|
|
141
|
+
| `shellRun` | a command on the ground's machine | `root` alone |
|
|
142
|
+
| `pilotsInvite`, `pilotsDismiss`, `pilotsList` | who pilots the ground | `root` alone |
|
|
143
|
+
| `boot` | the ladder stood and every house opened, as each boot asks | `root` alone |
|
|
144
|
+
|
|
145
|
+
**An ask of the dock is safe to send twice.** A request may carry
|
|
146
|
+
`call`, its call id. The same id sent again answers what the first
|
|
147
|
+
answered, and runs nothing twice.
|
|
148
|
+
|
|
149
|
+
**It lets a pilot possess it from afar.** `pilotsInvite` mints an
|
|
150
|
+
invitation to the dock's steward, and the owner hands it to one being.
|
|
151
|
+
That being then holds a standing on the dock, and asks the houses and
|
|
152
|
+
faculties asks through it. Her class reaches them typed with
|
|
153
|
+
`this.held(id, DockPilot)`, the need `nervur` exports. Secrets, moves,
|
|
154
|
+
the shell and faculties' methods stay the hand's alone. A secret passes
|
|
155
|
+
through `secretsSet`, which answers nothing, so no answer holds one.
|
|
156
|
+
|
|
157
|
+
**It moves a house by its seed and its memory.** `movesOut` takes a
|
|
158
|
+
house out as its seed and every place of its memory, and another ground
|
|
159
|
+
takes them in with `movesIn`. The house keeps its identity, so every
|
|
160
|
+
relation still answers and no far house notices.
|
|
85
161
|
|
|
86
162
|
## The five grounds
|
|
87
163
|
|
|
88
|
-
| Ground | Where it runs | When it wakes | Its unlock | Its memory |
|
|
89
|
-
| --- | --- | --- | --- | --- |
|
|
90
|
-
| NodeGround | a server, a desktop, a Pi | always on | a key file, or the macOS keychain | a ledger in its folder |
|
|
91
|
-
| EdgeGround | a Cloudflare Worker and its Durable Object | per request, per message, per alarm | the Worker's secret | the object's storage |
|
|
92
|
-
| BrowserGround | a page or its service worker | while a tab is open, and by push | a key sealed under one the browser never hands out | IndexedDB |
|
|
93
|
-
| AppGround | an iOS or Android app's web view | per launch, and by push | the Keychain or the Keystore | the app's native store |
|
|
94
|
-
| BenchGround | memory, in a test | as the test moves its clock | a key drawn from the bench's seed | memory in the process |
|
|
164
|
+
| Ground | Where it runs | When it wakes | Its unlock | Its memory | Its hand |
|
|
165
|
+
| --- | --- | --- | --- | --- | --- |
|
|
166
|
+
| NodeGround | a server, a desktop, a Pi | always on | a key file, or the macOS keychain | a ledger in its folder | a socket in its folder |
|
|
167
|
+
| EdgeGround | a Cloudflare Worker and its Durable Object | per request, per message, per alarm | the Worker's secret | the object's storage | a key the Worker holds |
|
|
168
|
+
| BrowserGround | a page or its service worker | while a tab is open, and by push | a key sealed under one the browser never hands out | IndexedDB | a channel between the origin's tabs |
|
|
169
|
+
| AppGround | an iOS or Android app's web view | per launch, and by push | the Keychain or the Keystore | the app's native store | a channel, as in a page |
|
|
170
|
+
| BenchGround | memory, in a test | as the test moves its clock | a key drawn from the bench's seed | memory in the process | the test's own |
|
|
95
171
|
|
|
96
172
|
The same class runs unchanged on every row. What differs is the bodies
|
|
97
173
|
each ground hands its houses.
|
|
@@ -108,11 +184,30 @@ shows. The ground's folder is an ES module package, so its
|
|
|
108
184
|
port is set, on the web. [The command](COMMAND.md) lists its settings
|
|
109
185
|
and runs its hand.
|
|
110
186
|
|
|
111
|
-
**Its registry
|
|
112
|
-
classes from a folder inside
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
187
|
+
**Its registry holds its terrain's faculties.** `folder` serves each
|
|
188
|
+
house its classes from a folder inside the code folder its args name.
|
|
189
|
+
Its body carries a registry of two more, rooted there. `module` imports
|
|
190
|
+
a module as a registry, whose `faculties` export holds `{ up, install?
|
|
191
|
+
}` by name. `bridge` starts a program, in any language, and hands it the
|
|
192
|
+
secrets its entry names as its environment. An entry stands either with
|
|
193
|
+
`from: 'folder'`. `tcp` and `web` are its carries, `listener` its one
|
|
194
|
+
listener, and `shell` its shell. Its clock is the library's, and
|
|
195
|
+
primordial.
|
|
196
|
+
|
|
197
|
+
**Its code gives the default entries.** `folder`, `listener`, `tcp`,
|
|
198
|
+
`web` and `shell` stand from entries the library fixes. TCP
|
|
199
|
+
listens on the loopback at 9110, so nothing beyond the machine reaches
|
|
200
|
+
a new ground. A server names its bind through the hand. The web names
|
|
201
|
+
`listener` in its `faculties` and listens on no port. An entry of the
|
|
202
|
+
same name you land stands in their place, so a port changes through the
|
|
203
|
+
hand. Name
|
|
204
|
+
`listener` there too, since the web serves the listener it calls.
|
|
205
|
+
|
|
206
|
+
**A port another process holds keeps that carry down with why.** The
|
|
207
|
+
ground boots beside it until the hand moves the port. A `tcp` entry
|
|
208
|
+
whose args name no port only dials, and its invitations name no TCP
|
|
209
|
+
address. Its environment names only `NERVUR_STATE`, `NERVUR_UNLOCK` and
|
|
210
|
+
`NERVUR_HAND`.
|
|
116
211
|
|
|
117
212
|
**Its key rests in `state/key`, its owner's alone.** A key file others
|
|
118
213
|
may read is refused, as ssh refuses a key. On macOS,
|
|
@@ -120,10 +215,17 @@ may read is refused, as ssh refuses a key. On macOS,
|
|
|
120
215
|
instead. Keep `state/` as you keep an ssh key: whoever holds the key and
|
|
121
216
|
the ledger holds the ground.
|
|
122
217
|
|
|
123
|
-
**It keeps its memory as a ledger
|
|
124
|
-
the line before it and synced before it
|
|
125
|
-
but its end is refused. A witness file
|
|
126
|
-
restored copy that is behind.
|
|
218
|
+
**It keeps its memory as a ledger, which holds the folder's lock.** Every
|
|
219
|
+
write is one line, chained to the line before it and synced before it
|
|
220
|
+
counts. A ledger edited anywhere but its end is refused. A witness file
|
|
221
|
+
kept on another disk refuses a restored copy that is behind. While the
|
|
222
|
+
ledger stands, a second ground on the same state is refused.
|
|
223
|
+
|
|
224
|
+
**Its shell runs a command for the hand alone.** `nervur shell run --
|
|
225
|
+
<command>` runs it in the code folder, and answers its exit code and
|
|
226
|
+
what it printed. Its environment holds `PATH`, `HOME` and a few more of
|
|
227
|
+
the process's, and never a secret or a `NERVUR_` variable. No pilot and
|
|
228
|
+
no being reaches it.
|
|
127
229
|
|
|
128
230
|
**It runs a program as a faculty, in any language.** The bridge starts a
|
|
129
231
|
program and speaks one JSON value a line on its standard streams. The
|
|
@@ -151,24 +253,24 @@ export default EdgeGround.worker();
|
|
|
151
253
|
```
|
|
152
254
|
|
|
153
255
|
The Worker binds the object's class as `GROUND`, with SQLite storage.
|
|
154
|
-
`registry` joins the terrain's own, so an entry
|
|
155
|
-
`from`. A house's entry names its code with `classes: {
|
|
156
|
-
at: 'shop' }`.
|
|
256
|
+
`registry` joins the terrain's own, so an entry raises `payments` with
|
|
257
|
+
no `from`. A house's entry names its code with `classes: { faculty:
|
|
258
|
+
'bundle', at: 'shop' }`.
|
|
157
259
|
|
|
158
|
-
**Its
|
|
260
|
+
**Its Worker holds two secrets and nothing else.**
|
|
159
261
|
|
|
160
|
-
|
|
|
262
|
+
| Variable | What it names |
|
|
161
263
|
| --- | --- |
|
|
162
264
|
| `NERVUR_SECRET` | the ground's key, sixty-four hex digits; set as a secret |
|
|
163
265
|
| `NERVUR_HAND` | the key its hand answers; set as a secret |
|
|
164
|
-
| `NERVUR_ADDRESSES` | the addresses it is reached at, by commas, the held line first |
|
|
165
|
-
| `NERVUR_ORIGINS` | the page origins it answers |
|
|
166
|
-
| `NERVUR_ALLOW_PRIVATE` | `1` to let it dial a private address |
|
|
167
|
-
| `NERVUR_WAIT` | the longest any ask may run, a minute where unset |
|
|
168
266
|
|
|
169
267
|
A Worker learns no name it is reached by, so it writes only the
|
|
170
|
-
addresses `
|
|
171
|
-
|
|
268
|
+
addresses its `web` entry names, the held line first. Name them through
|
|
269
|
+
the hand with `facultiesUpdate`, as `addresses` in the args of `web`,
|
|
270
|
+
beside its `origins` and `allowPrivate`, and the dock keeps them.
|
|
271
|
+
Every ask runs a minute at most, and `waitSet` keeps a shorter bound.
|
|
272
|
+
Its faculties take their secrets from the dock, as on every ground. It
|
|
273
|
+
has no shell.
|
|
172
274
|
|
|
173
275
|
**Its hand answers its key alone.** The hand is `POST /nervur/hand`, with
|
|
174
276
|
the key as a bearer token and one request as the body. Every other
|
|
@@ -190,18 +292,19 @@ the object. A watch held on that line answers the moment the change lands.
|
|
|
190
292
|
|
|
191
293
|
**A BrowserGround is one ground for its origin.** Every tab and the
|
|
192
294
|
service worker of an origin share it. The tab holding a Web Lock runs
|
|
193
|
-
the ground, and every other tab
|
|
194
|
-
answers no face. Whoever serves the origin's script
|
|
195
|
-
ground, so its origin serves nothing else.
|
|
295
|
+
the ground, and its hand answers every other tab over a channel. It
|
|
296
|
+
only dials, so it answers no face. Whoever serves the origin's script
|
|
297
|
+
possesses the ground, so its origin serves nothing else.
|
|
196
298
|
[The package's start](README.md) opens one in a page.
|
|
197
299
|
|
|
198
300
|
**Its registry is the one the page hands.** `BrowserGround.open({
|
|
199
|
-
registry })` joins it to the terrain's own, whose
|
|
200
|
-
house
|
|
301
|
+
registry })` joins it to the terrain's own, whose faculty `origin`
|
|
302
|
+
serves each house its classes from the origin.
|
|
201
303
|
|
|
202
|
-
**An AppGround is a BrowserGround with the shell's bodies.** The
|
|
203
|
-
hands in two small interfaces, one for secrets and one for
|
|
204
|
-
the library holds the rest. The ground's key rests in the
|
|
304
|
+
**An AppGround is a BrowserGround with the shell's bodies.** The app's
|
|
305
|
+
native shell hands in two small interfaces, one for secrets and one for
|
|
306
|
+
a store, and the library holds the rest. The ground's key rests in the
|
|
307
|
+
secret store.
|
|
205
308
|
|
|
206
309
|
## BenchGround
|
|
207
310
|
|
package/README.md
CHANGED
|
@@ -96,11 +96,11 @@ Run the ground in the folder, and leave it running.
|
|
|
96
96
|
npx nervur up .
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
In a second shell, add the house once. The ground keeps its entry
|
|
100
|
-
sealed
|
|
99
|
+
In a second shell, add the house once. The ground keeps its entry as a
|
|
100
|
+
sealed cell of its dock, and opens it again at every start.
|
|
101
101
|
|
|
102
102
|
```bash
|
|
103
|
-
npx nervur houses add name=main classes='{"
|
|
103
|
+
npx nervur houses add name=main classes='{"faculty":"folder","at":"house"}'
|
|
104
104
|
```
|
|
105
105
|
|
|
106
106
|
Then ask the steward through the ground's hand.
|
|
@@ -130,9 +130,8 @@ const ground = await BrowserGround.open();
|
|
|
130
130
|
|
|
131
131
|
// The house's code is a module on this origin, and its rows rest sealed in IndexedDB.
|
|
132
132
|
await ground.hand({
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
args: { name: 'main', classes: { body: 'origin', at: '/house/index.js' } },
|
|
133
|
+
method: 'housesAdd',
|
|
134
|
+
args: { name: 'main', classes: { faculty: 'origin', at: '/house/index.js' } },
|
|
136
135
|
});
|
|
137
136
|
|
|
138
137
|
console.log(await ground.hand({ house: 'main', method: 'hello', args: { name: 'Ada' } }));
|
|
@@ -154,10 +153,11 @@ keeps. [Writing for nervur](AUTHORING.md) shows both.
|
|
|
154
153
|
| Entry | For |
|
|
155
154
|
| --- | --- |
|
|
156
155
|
| `nervur/being` | writing a being: `Being`, `s`, `need`, `tableOf`, `Args`, `Result`, `Json`, `Table` |
|
|
157
|
-
| `nervur` | any engine: `Ground`, `House` and the bodies they take |
|
|
156
|
+
| `nervur` | any engine: `Ground`, `House`, `DockPilot`, `vouchesOf` and the bodies they take |
|
|
158
157
|
| `nervur/node` | a ground on Node: `NodeGround`, the `nervur` command, and its bodies |
|
|
159
158
|
| `nervur/browser` | a ground in a page or its service worker: `BrowserGround` and its bodies |
|
|
160
|
-
| `nervur/
|
|
159
|
+
| `nervur/edge` | a ground on the edge, a Worker and its Durable Object: `EdgeGround` and its bodies |
|
|
160
|
+
| `nervur/app` | a ground in a phone's app: `AppGround`, and the three interfaces its shell fills: `NativeShell`, `NativeSecrets` and `NativeStore` |
|
|
161
161
|
| `nervur/serve` | a faculty's program in JavaScript: `serve` |
|
|
162
162
|
| `nervur/bench` | tests: `Bench`, `BenchGround` and `FakeNetwork` |
|
|
163
163
|
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { ClassList, Ground, type
|
|
1
|
+
import { ClassList, Ground, type Body, type Registry } from '../index.ts';
|
|
2
2
|
import { FakeMemory } from './fake-memory.ts';
|
|
3
3
|
import { type FakeNetwork } from './fake-network.ts';
|
|
4
4
|
import { FakeUnlock } from './fake-unlock.ts';
|
|
5
5
|
import { SeededCrypto } from './seeded.ts';
|
|
6
6
|
type BeingClass = ConstructorParameters<typeof ClassList>[0]['steward'];
|
|
7
7
|
type Entry = Parameters<Ground['add']>[1];
|
|
8
|
-
type HandAsk = Parameters<Ground['ask']>[0];
|
|
9
8
|
type Standing = Awaited<ReturnType<Ground['add']>>;
|
|
10
9
|
/** A house module: what a folder's index exports. */
|
|
11
10
|
export interface HouseModule {
|
|
@@ -13,8 +12,8 @@ export interface HouseModule {
|
|
|
13
12
|
readonly public?: BeingClass;
|
|
14
13
|
readonly beings?: readonly BeingClass[];
|
|
15
14
|
}
|
|
16
|
-
/** A
|
|
17
|
-
export type Living =
|
|
15
|
+
/** A body the test writes, living, with the kinds it is granted. */
|
|
16
|
+
export type Living = Body & {
|
|
18
17
|
readonly kinds?: readonly string[];
|
|
19
18
|
};
|
|
20
19
|
/** What a ground keeps across its lives: its key, its randomness, its memory, and each house's own where it names the `fake` body. */
|
|
@@ -61,8 +60,9 @@ export declare class BenchGround {
|
|
|
61
60
|
add(name: string, from?: string | Entry, rest?: Omit<Entry, 'classes'>): Promise<Standing>;
|
|
62
61
|
remove(name: string): Promise<void>;
|
|
63
62
|
list(): readonly Standing[];
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
/** A being in a house asked as `root`, the house's steward where no id is named. */
|
|
64
|
+
ask(request: Parameters<Ground['ask']>[0]): ReturnType<Ground['ask']>;
|
|
65
|
+
/** The ground's hand, as its owner holds it: `describe`, or an ask of a being in a house, or of the dock's steward where no house is named. */
|
|
66
66
|
hand(request: Parameters<Ground['hand']>[0]): ReturnType<Ground['hand']>;
|
|
67
67
|
/**
|
|
68
68
|
* A request to the ground's one listener, with no socket: each faculty's
|