nervur 0.22.2-5 → 0.22.2-7
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 +193 -102
- package/COMMAND.md +128 -0
- package/FACES.md +275 -0
- package/FACULTIES.md +558 -0
- package/GROUNDS.md +212 -0
- package/KIT-SPEC.md +26 -8
- package/README.md +30 -21
- package/WORLD.md +195 -0
- package/dist/app/app-ground.d.ts +2 -2
- package/dist/app/app-ground.js +7 -9
- package/dist/app/index.d.ts +2 -2
- package/dist/app/index.js +1 -1
- package/dist/app/native.d.ts +9 -44
- package/dist/app/native.js +7 -95
- package/dist/being/being.d.ts +84 -7
- package/dist/being/being.js +1 -1
- package/dist/being/index.d.ts +2 -1
- package/dist/being/index.js +1 -0
- package/dist/being/table.d.ts +6 -0
- package/dist/being/table.js +72 -16
- package/dist/bench/bench-ground.d.ts +35 -17
- package/dist/bench/bench-ground.js +52 -28
- package/dist/bench/bench.d.ts +43 -29
- package/dist/bench/bench.js +240 -132
- package/dist/bench/fake-clock.d.ts +1 -1
- package/dist/bench/fake-memory.d.ts +3 -1
- package/dist/bench/fake-network.d.ts +16 -7
- package/dist/bench/fake-network.js +67 -14
- package/dist/bench/fake-unlock.d.ts +6 -0
- package/dist/bench/fake-unlock.js +10 -0
- package/dist/bench/index.d.ts +3 -11
- package/dist/bench/index.js +2 -10
- package/dist/bench/seeded.d.ts +1 -1
- package/dist/bench/seeded.js +1 -1
- package/dist/bench/stewards.d.ts +157 -5
- package/dist/bench/stewards.js +115 -7
- package/dist/bodies/joined-carry.d.ts +7 -1
- package/dist/bodies/joined-carry.js +9 -3
- package/dist/bodies/kept.d.ts +44 -0
- package/dist/bodies/kept.js +91 -0
- package/dist/bodies/vouch.d.ts +20 -0
- package/dist/bodies/vouch.js +71 -0
- package/dist/bodies/web-carry.d.ts +9 -2
- package/dist/bodies/web-carry.js +30 -9
- package/dist/browser/browser-ground.d.ts +16 -9
- package/dist/browser/browser-ground.js +29 -28
- package/dist/browser/index.d.ts +3 -3
- package/dist/browser/index.js +1 -1
- package/dist/browser/{locked-custody.d.ts → locked-unlock.d.ts} +6 -9
- package/dist/browser/{locked-custody.js → locked-unlock.js} +29 -37
- package/dist/edge/durable-clock.d.ts +19 -0
- package/dist/edge/durable-clock.js +61 -0
- package/dist/edge/durable-memory.d.ts +5 -0
- package/dist/edge/durable-memory.js +11 -0
- package/dist/edge/durable.d.ts +18 -0
- package/dist/edge/durable.js +24 -0
- package/dist/edge/edge-ground.d.ts +49 -0
- package/dist/edge/edge-ground.js +199 -0
- package/dist/edge/index.d.ts +7 -0
- package/dist/edge/index.js +9 -0
- package/dist/edge/native-crypto.d.ts +8 -0
- package/dist/edge/native-crypto.js +102 -0
- package/dist/edge/secret-unlock.d.ts +7 -0
- package/dist/edge/secret-unlock.js +13 -0
- package/dist/edge/socket-carry.d.ts +39 -0
- package/dist/edge/socket-carry.js +111 -0
- package/dist/foundation.d.ts +12 -0
- package/dist/ground/ground.d.ts +199 -40
- package/dist/ground/ground.js +678 -203
- package/dist/ground/views.d.ts +59 -0
- package/dist/ground/views.js +188 -0
- package/dist/house/crossing.d.ts +18 -6
- package/dist/house/crossing.js +35 -14
- package/dist/house/house.d.ts +26 -28
- package/dist/house/house.js +405 -167
- package/dist/house/rows-shape.d.ts +8 -1
- package/dist/index.d.ts +9 -6
- package/dist/index.js +3 -1
- package/dist/node/bridge.d.ts +3 -0
- package/dist/node/bridge.js +113 -17
- package/dist/node/cli.js +43 -21
- package/dist/node/hand.d.ts +2 -0
- package/dist/node/hand.js +4 -2
- package/dist/node/index.d.ts +6 -8
- package/dist/node/index.js +1 -3
- package/dist/node/node-ground.d.ts +6 -12
- package/dist/node/node-ground.js +71 -56
- package/dist/node/tcp-carry.d.ts +8 -7
- package/dist/node/tcp-carry.js +21 -53
- package/dist/node/unlock.d.ts +17 -0
- package/dist/node/unlock.js +86 -0
- package/dist/node/websocket.d.ts +8 -2
- package/dist/node/websocket.js +20 -4
- package/dist/quo/frame.d.ts +13 -0
- package/dist/quo/frame.js +44 -0
- package/dist/quo/index.d.ts +1 -0
- package/dist/quo/index.js +5 -0
- package/dist/serve/index.d.ts +27 -9
- package/dist/serve/index.js +24 -8
- package/package.json +12 -2
- package/dist/bench/fake-carry.d.ts +0 -32
- package/dist/bench/fake-carry.js +0 -56
- package/dist/bench/fake-custody.d.ts +0 -9
- package/dist/bench/fake-custody.js +0 -10
- package/dist/bench/fake-faculty.d.ts +0 -25
- package/dist/bench/fake-faculty.js +0 -48
- package/dist/bench/fake-keys.d.ts +0 -5
- package/dist/bench/fake-keys.js +0 -9
- package/dist/node/custody.d.ts +0 -20
- package/dist/node/custody.js +0 -34
- package/dist/node/file-keys.d.ts +0 -7
- package/dist/node/file-keys.js +0 -30
- package/dist/node/held-keys.d.ts +0 -14
- package/dist/node/held-keys.js +0 -36
- package/dist/node/keychain-keys.d.ts +0 -10
- package/dist/node/keychain-keys.js +0 -51
package/AUTHORING.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# Writing for nervur
|
|
2
2
|
|
|
3
3
|
This guide teaches the two things you write with `nervur`. A **being**
|
|
4
|
-
holds logic and state. A **faculty** reaches the world outside
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
package's own tests run.
|
|
4
|
+
holds logic and state. A **faculty** reaches the world outside, and
|
|
5
|
+
[Writing a faculty](FACULTIES.md) teaches it whole. A **ground** runs them on
|
|
6
|
+
a machine, and the library ships it. The examples build one small shop,
|
|
7
|
+
and every file here is a file the package's own tests run.
|
|
8
8
|
|
|
9
9
|
The shop has three classes and one faculty.
|
|
10
10
|
|
|
11
11
|
- `Order` is one order, from its first item to its shipping.
|
|
12
12
|
- `Shop` is the steward, the being that runs the house.
|
|
13
13
|
- `Lobby` is the public being, which strangers may ask.
|
|
14
|
-
- `Payments` is a faculty that charges money, which
|
|
14
|
+
- `Payments` is a faculty that charges money, which a maker in
|
|
15
15
|
`recipe.ts` makes.
|
|
16
16
|
|
|
17
17
|
## Words
|
|
@@ -31,7 +31,8 @@ The shop has three classes and one faculty.
|
|
|
31
31
|
| role | a named test over the asker and her cells |
|
|
32
32
|
| state | a name read from her cells that decides which asks exist |
|
|
33
33
|
| house | what holds beings, keeps their cells, and seals every ask |
|
|
34
|
-
| ground | the process houses run in, holding their seeds, faculties and
|
|
34
|
+
| ground | the process houses run in, holding one key and sealing their seeds, faculties and secrets under it |
|
|
35
|
+
| registry | code that makes faculties and bodies by name, for the ground to stand |
|
|
35
36
|
|
|
36
37
|
## A being
|
|
37
38
|
|
|
@@ -169,7 +170,7 @@ JavaScript writes nothing.
|
|
|
169
170
|
| `args` | the schema of what it takes; omitted, the empty object alone |
|
|
170
171
|
| `result` | the schema of what it answers; omitted, nothing |
|
|
171
172
|
| `hints` | `readOnly`, `idempotent`, `destructive` |
|
|
172
|
-
| `examples` |
|
|
173
|
+
| `examples` | a history of her asks, a role, args, fakes, and what it gives |
|
|
173
174
|
| `description` | one line for readers and agents |
|
|
174
175
|
| `wait` | milliseconds she may run; omitted, thirty seconds |
|
|
175
176
|
|
|
@@ -202,6 +203,9 @@ nothing lands.
|
|
|
202
203
|
| `this.house.cancelAlarm({ key })` | an alarm removed |
|
|
203
204
|
| `this.<need>.<method>({…}, { reply? })` | an awaited call, or an effect |
|
|
204
205
|
| `this.held(id, Need).<ask>({…}, { reply?, after? })` | the same, on a standing, and a watch where `after` is given |
|
|
206
|
+
| `this.held(id).describe()`, `.ask(method, {…}, options)` | a standing with no need: what it shows her, then any ask it showed |
|
|
207
|
+
| `this.stranger({ ward, at }, Need).<ask>({…})` | a far house's public being, asked as a stranger, every ask awaited |
|
|
208
|
+
| `this.stranger({ ward, at }).describe()`, `.ask(method, {…})` | the same with no need: what she shows a stranger, then any ask it showed |
|
|
205
209
|
| `this.standings` | `list()`, `note(id, notes)` and `drop(id)` |
|
|
206
210
|
| `this.handle(ask, { bind?, notes?, once?, expires? })` | a handle to one of her asks |
|
|
207
211
|
| `this.invite(id, { notes?, expires? })` | a new occupant, as a handle |
|
|
@@ -261,6 +265,12 @@ hold: `{ result: [...] }`. From a being, pass the result she holds:
|
|
|
261
265
|
`readOnly` ask is watched, and a watch on anything else is refused where
|
|
262
266
|
she makes it.
|
|
263
267
|
|
|
268
|
+
A watch may land as a reply instead: `{ after: seen, reply: 'heard' }`.
|
|
269
|
+
It leaves once her ask lands, as an effect does, and its answer asks her
|
|
270
|
+
`heard`, where she writes what she heard and watches again. So a device
|
|
271
|
+
that only dials, a phone or a Pi behind a router, hears its station the
|
|
272
|
+
moment something changes there, and opens no port.
|
|
273
|
+
|
|
264
274
|
A watch moves only on what its asker could read, since it runs as that
|
|
265
275
|
asker. One asker holds one watch on one ask with the same args, and a
|
|
266
276
|
second answers the first at once. A watch across a door holds its
|
|
@@ -277,7 +287,11 @@ An **occupant** is someone who may ask her. She mints one with
|
|
|
277
287
|
A **standing** is someone she may ask. She receives one where an ask's
|
|
278
288
|
args carry an invitation under `s.handle`, or where her steward
|
|
279
289
|
introduces one. She asks through it with `this.held(id, Need)`, which
|
|
280
|
-
checks the standing's describe covers the need.
|
|
290
|
+
checks the standing's describe covers the need. A standing from an
|
|
291
|
+
invitation is named `standing:` and sixteen hex digits, and the id is
|
|
292
|
+
what her ask receives. One her steward introduced is named by the being
|
|
293
|
+
it reaches. She asks a far standing from the ask after the one that took
|
|
294
|
+
it.
|
|
281
295
|
|
|
282
296
|
Every relation carries two sets of notes. `notes` are hers alone.
|
|
283
297
|
`steward` are her steward's, written when the steward made the relation,
|
|
@@ -365,13 +379,14 @@ export class Shop extends Being.of({
|
|
|
365
379
|
| `bear({ kind, id, args })` | places a new being; the same id twice answers the first |
|
|
366
380
|
| `remove({ id })` | removes a being and everything of hers |
|
|
367
381
|
| `list()` | every being, her kind, whether she is absent, and her dead letters |
|
|
368
|
-
| `ask({ id, method, args }, { reply? })` | asks any being as her occupant `steward
|
|
382
|
+
| `ask({ id, method, args }, { reply? })` | asks any being as her occupant `steward`; with no method, reads what she shows the steward |
|
|
369
383
|
| `introduce({ from, to, notes })` | gives `from` a standing on `to`, and `to` an occupant |
|
|
370
384
|
| `invite({ id, occupant, notes, expires? })` | gives a being a new occupant, and the steward its handle |
|
|
371
385
|
|
|
372
386
|
`bear`, `remove`, `introduce` and `invite` land in the steward's own
|
|
373
387
|
write. If her ask fails, none of them happened. A being borne runs her
|
|
374
|
-
`born` ask first, where her class declares one
|
|
388
|
+
`born` ask first, where her class declares one, asked as the occupant
|
|
389
|
+
`steward`, so its entry says `for: 'steward'`.
|
|
375
390
|
|
|
376
391
|
Every other being is placed as `normal`. She holds the standing
|
|
377
392
|
`steward` and the occupant `steward`, and can drop neither.
|
|
@@ -469,10 +484,19 @@ hold.
|
|
|
469
484
|
Every need is covered, or she is absent. An absent being answers silence
|
|
470
485
|
and keeps her cells, and answers again once an offer covers her needs.
|
|
471
486
|
|
|
487
|
+
A standing is matched to a need by rules two to four alone. A describe
|
|
488
|
+
names no blueprint, so the need's name is hers to choose there.
|
|
489
|
+
|
|
490
|
+
A need she forgot to declare is a member she does not hold, and the call
|
|
491
|
+
throws inside her ask, which answers only `the ask failed`. So check your
|
|
492
|
+
classes with `npx tsc --noEmit` beside your tests, which run with
|
|
493
|
+
`node --test`.
|
|
494
|
+
|
|
472
495
|
### Testing on the bench
|
|
473
496
|
|
|
474
|
-
The bench opens two houses
|
|
475
|
-
and
|
|
497
|
+
The bench opens two houses on one ground in memory, on fake memory,
|
|
498
|
+
keys and clock. A being of the bench's own house asks hers through a
|
|
499
|
+
door, so every ask crosses as it would in production.
|
|
476
500
|
|
|
477
501
|
```ts
|
|
478
502
|
// order.test.ts
|
|
@@ -495,38 +519,49 @@ test('An order is paid once the provider calls the handle it was given', async (
|
|
|
495
519
|
assert.deepEqual(await order.ask('add', { sku: 'tea', price: 4 }), { result: { total: 4 } });
|
|
496
520
|
assert.deepEqual(await order.ask('checkout'), { result: null });
|
|
497
521
|
await bench.settle();
|
|
498
|
-
assert.equal((await order.
|
|
522
|
+
assert.equal((await order.describe())?.state, 'paying', 'the charge left once checkout landed, and answered pending');
|
|
499
523
|
|
|
500
524
|
assert.deepEqual(await payments.settle('first'), { result: null });
|
|
501
525
|
await bench.settle();
|
|
502
|
-
assert.equal((await order.
|
|
526
|
+
assert.equal((await order.describe())?.state, 'paid');
|
|
503
527
|
assert.deepEqual(await order.ask('add', { sku: 'jam', price: 1 }), { error: { message: 'not in this state' } });
|
|
504
528
|
});
|
|
505
529
|
```
|
|
506
530
|
|
|
507
|
-
`place(Class, { id,
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
531
|
+
`place(Class, { id, born })` has the bench's steward bear a being. A
|
|
532
|
+
placed being is asked with `ask(method, args, { role })` and described
|
|
533
|
+
with `describe({ role })`. Test her through her asks first, as every
|
|
534
|
+
asker meets her. `cells()` reads her cells through the hand, as her owner
|
|
535
|
+
inspects them. An effect answers with the reply it brings once it lands.
|
|
536
|
+
`settle()` lets every effect and reply run, and `advance(ms)` moves the
|
|
537
|
+
fake clock.
|
|
538
|
+
|
|
539
|
+
The bench plays a role as an owner could, judged on her cells as they
|
|
540
|
+
stand. `root`, and a role root holds, is the hand. `steward` is the
|
|
541
|
+
bench's steward, and `being` a being it introduces to her. Any other
|
|
542
|
+
role is an occupant the bench's steward invites, with the role `true` in
|
|
543
|
+
its steward notes. A role read from her own notes is hers to grant, and
|
|
544
|
+
a handle only her own ask mints.
|
|
514
545
|
|
|
515
546
|
A steward and a public being are placed where the house places them.
|
|
516
547
|
`Bench.open({ steward: Shop, public: Lobby, classes: [Order] })` opens the
|
|
517
548
|
author's house with them there, and `place(Shop)` and `place(Lobby)` find
|
|
518
|
-
them.
|
|
519
|
-
the
|
|
520
|
-
|
|
549
|
+
them. On the public being, a role a stranger holds is played by a being
|
|
550
|
+
of the bench's own house, asking as a stranger. Beside a steward the test
|
|
551
|
+
brings, the bench plays `root` and `stranger` alone, and places no other
|
|
552
|
+
being. A world of your steward and the beings she bears is tested on a
|
|
553
|
+
BenchGround, as [Faces](FACES.md) tests its desk.
|
|
521
554
|
`Bench.check(Shop, { position: 'steward' })` and `Bench.check(Lobby, {
|
|
522
|
-
position: 'public'
|
|
555
|
+
position: 'public' })` check them.
|
|
523
556
|
|
|
524
|
-
An entry's `examples` are tests the bench runs. Each is
|
|
525
|
-
fresh bench
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
557
|
+
An entry's `examples` are tests the bench runs. Each is a history, then
|
|
558
|
+
one ask, on a fresh bench. `given` lists the asks of hers that bring her
|
|
559
|
+
from her `born` to where the example starts. `role` asks, `args` are the
|
|
560
|
+
ask's, `fakes` answer her needs, and `gives` is the answer owed.
|
|
561
|
+
`Bench.check` runs every example twice from one seed and flags a class
|
|
562
|
+
that answers differently, or leaves her cells differently. It then
|
|
563
|
+
describes every state to every role it plays, and names every finding
|
|
564
|
+
that failed.
|
|
530
565
|
|
|
531
566
|
## A faculty
|
|
532
567
|
|
|
@@ -553,7 +588,8 @@ type Answer = { result: { pending: boolean } } | { error: { message: string } };
|
|
|
553
588
|
/**
|
|
554
589
|
* A payment provider in the ground's process. It answers a call id it has
|
|
555
590
|
* seen with the answer it gave, so an effect sent twice charges once. A
|
|
556
|
-
* provider that changes the world keeps these
|
|
591
|
+
* provider that changes the world keeps these in the memory its maker
|
|
592
|
+
* receives, where a restart and a move keep them.
|
|
557
593
|
*/
|
|
558
594
|
export class Payments {
|
|
559
595
|
readonly #answered = new Map<string, Answer>();
|
|
@@ -581,55 +617,31 @@ export class Payments {
|
|
|
581
617
|
export const paymentsOffer = (payments: Payments): Offer => ({ blueprint: PaymentsBlueprint, object: payments, window: 7 * 86_400_000 });
|
|
582
618
|
```
|
|
583
619
|
|
|
584
|
-
An offer is `{ blueprint, object, kinds?, window
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
answers a call id it has seen with the answer it gave.
|
|
592
|
-
- **A handle arrives as a token.** The faculty calls it with
|
|
593
|
-
`context.call({ token, args, id })`. Its own `id` makes that call run
|
|
594
|
-
once, however often it is sent.
|
|
595
|
-
- **`kinds` is the ground's grant.** It lists the classes that may hold
|
|
596
|
-
the offer. Without it, every class whose need it covers holds it.
|
|
597
|
-
- **`window` is how long the faculty remembers a call id.** It is seven
|
|
598
|
-
days where omitted, and the house gives up on an effect at it.
|
|
599
|
-
- **`handler` answers HTTP on the ground's one listener.** It takes a
|
|
600
|
-
`Request` and answers a `Response`, or `null` where the request is not
|
|
601
|
-
its own. A site, an API or an MCP server is a faculty with a handler.
|
|
602
|
-
- **`stop` is called when the ground stops**, faculties in the reverse of
|
|
603
|
-
the order they were made.
|
|
604
|
-
|
|
605
|
-
The object arrives living. The ground makes and starts the faculty, and
|
|
606
|
-
the house never starts, stops or restarts it. Every being whose need it
|
|
607
|
-
covers holds the same object.
|
|
608
|
-
|
|
609
|
-
A faculty is the ground's, never a house's. The ground's recipe makes
|
|
610
|
-
each one by name, from the settings the ground hands it. `env` is the
|
|
611
|
-
ground's environment, so a secret stays on its machine and out of the
|
|
612
|
-
code. `dir(name)` answers a folder of the faculty's own.
|
|
620
|
+
An offer is `{ blueprint, object, kinds?, window? }`. The object answers
|
|
621
|
+
each call with its call id, and one that changes the world answers a
|
|
622
|
+
call id it has seen with the answer it gave. A registry holds a maker
|
|
623
|
+
for each faculty by name. The ground stands a faculty when an entry names
|
|
624
|
+
its maker, and the entry's `kinds` grants it to the classes it names.
|
|
625
|
+
[Writing a faculty](FACULTIES.md) teaches the craft whole, with a faculty
|
|
626
|
+
written in Python.
|
|
613
627
|
|
|
614
628
|
```ts
|
|
615
629
|
// recipe.ts
|
|
616
630
|
import { Payments, paymentsOffer } from './payments.ts';
|
|
617
631
|
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
632
|
+
// A registry: the ground makes each faculty an entry names, by its maker here.
|
|
633
|
+
export const faculties = {
|
|
634
|
+
payments: () => paymentsOffer(new Payments()),
|
|
635
|
+
};
|
|
621
636
|
```
|
|
622
637
|
|
|
623
|
-
Policy over a faculty is written as a being. Limits, approvals and
|
|
624
|
-
quotas are not the faculty's. One being holds the raw faculty through
|
|
625
|
-
`kinds`, and every other being reaches her through a standing.
|
|
626
|
-
|
|
627
638
|
## A ground
|
|
628
639
|
|
|
629
640
|
A ground is the process houses run in, and you write none. `nervur up`
|
|
630
|
-
runs one on a folder:
|
|
631
|
-
|
|
632
|
-
|
|
641
|
+
runs one on a folder of code: a folder for each house, and each module
|
|
642
|
+
your entries name. It holds one key in `state/`, and keeps every entry
|
|
643
|
+
sealed in its drawer: which faculties stand, and which houses open on
|
|
644
|
+
which bodies.
|
|
633
645
|
|
|
634
646
|
### The shop's folder
|
|
635
647
|
|
|
@@ -641,6 +653,13 @@ nervur-ground/
|
|
|
641
653
|
state/ made by the ground, its owner's alone
|
|
642
654
|
```
|
|
643
655
|
|
|
656
|
+
The folder is a package of ECMAScript modules, so Node reads its
|
|
657
|
+
TypeScript as it is written, with no build step.
|
|
658
|
+
|
|
659
|
+
```bash
|
|
660
|
+
npm init -y && npm pkg set type=module && npm install nervur
|
|
661
|
+
```
|
|
662
|
+
|
|
644
663
|
A house's folder names what the house holds.
|
|
645
664
|
|
|
646
665
|
```ts
|
|
@@ -662,39 +681,65 @@ The ground boots in one order, and a stop is that order reversed, on an
|
|
|
662
681
|
interrupt and on `SIGTERM`.
|
|
663
682
|
|
|
664
683
|
1. **Lock.** One ground to its state.
|
|
665
|
-
2. **
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
684
|
+
2. **Key.** Its key is read from `state/key`, drawn there on the first
|
|
685
|
+
start.
|
|
686
|
+
3. **Drawer.** Its ledger opens, and the key opens its drawer.
|
|
687
|
+
4. **Ladder.** Each faculty its drawer names stands on its registry. One
|
|
688
|
+
that fails stays down, and says why.
|
|
689
|
+
5. **Houses.** Each house of the drawer opens on its bodies.
|
|
690
|
+
6. **Hook.** The listeners, then the hand on its socket.
|
|
691
|
+
7. **Ready.** It tells systemd it is up, where systemd waits.
|
|
670
692
|
|
|
671
693
|
It is set by its environment.
|
|
672
694
|
|
|
673
695
|
| Setting | What it sets |
|
|
674
696
|
| --- | --- |
|
|
675
|
-
| `NERVUR_TCP_PORT` | its TCP port,
|
|
697
|
+
| `NERVUR_TCP_PORT` | its TCP port, 9110 where unset |
|
|
676
698
|
| `NERVUR_HTTP_PORT` | its HTTP port, for Quo over the web and every handler; no HTTP where unset |
|
|
677
|
-
| `NERVUR_ADDRESSES` | the public addresses it writes into invitations, by commas |
|
|
699
|
+
| `NERVUR_ADDRESSES` | the public addresses it writes into invitations, by commas: `tcp`, `https`, `http`, `wss` or `ws` |
|
|
700
|
+
| `NERVUR_ORIGINS` | the pages of other origins it answers on the web, by commas; a page of its own host needs none |
|
|
701
|
+
| `NERVUR_ALLOW_PRIVATE` | `1` to dial private and loopback addresses, as two grounds on one machine do |
|
|
678
702
|
| `NERVUR_BIND` | the address it listens on, `0.0.0.0` where unset |
|
|
679
703
|
| `NERVUR_STATE` | its state, `state/` in its folder where unset |
|
|
680
|
-
| `
|
|
704
|
+
| `NERVUR_UNLOCK` | `keychain:<account>` keeps its key in the macOS keychain, in place of `state/key` |
|
|
681
705
|
| `NERVUR_WAIT` | its bound on every ask, in milliseconds |
|
|
682
706
|
|
|
683
|
-
The state holds
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
707
|
+
The state holds the key in a file its owner alone reads, and the
|
|
708
|
+
ground's ledger. Every house keeps its rows in that ledger, sealed. A
|
|
709
|
+
ledger appends every write and never rewrites one. Its witness keeps
|
|
710
|
+
where it last stood, and a ledger behind its witness is refused. So a
|
|
711
|
+
ledger restored alone cannot replay what a house already answered,
|
|
712
|
+
though a whole state folder restored with its witness is not seen. A
|
|
713
|
+
lost key is a lost ground.
|
|
714
|
+
|
|
715
|
+
The ladder stands once, and the ground stands it again at every start.
|
|
716
|
+
The first entry stands the folder's `recipe.ts` as a registry, by the
|
|
717
|
+
ground's own maker `module`. The second makes the payments from it.
|
|
718
|
+
|
|
719
|
+
```bash
|
|
720
|
+
npx nervur faculties add name=recipe make=module args='{"at":"recipe.ts"}'
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
```bash
|
|
724
|
+
npx nervur faculties add name=payments from=recipe make=payments
|
|
725
|
+
```
|
|
687
726
|
|
|
688
727
|
A house is added once, and the ground opens it again at every start.
|
|
689
728
|
|
|
690
729
|
```bash
|
|
691
|
-
npx nervur houses add name=shop
|
|
730
|
+
npx nervur houses add name=shop classes='{"body":"folder","at":"classes"}' faculties='["payments"]'
|
|
692
731
|
```
|
|
693
732
|
|
|
694
|
-
`
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
733
|
+
`classes` names the body of the house's code. `folder` is the ground's
|
|
734
|
+
own, and a registry may add more, a git repository among them. A house
|
|
735
|
+
keeps its rows in the ground's ledger unless its entry names a `memory`
|
|
736
|
+
body. `faculties` names what the house receives, and within it each
|
|
737
|
+
faculty's entry names in `kinds` the classes that hold it.
|
|
738
|
+
|
|
739
|
+
A secret reaches a faculty the same way, and never through the
|
|
740
|
+
environment. `npx nervur secrets set -` reads `{ name, value }` from
|
|
741
|
+
standard input into the ground's sealed drawer. A faculty's entry names
|
|
742
|
+
the secrets its maker receives in `secrets`.
|
|
698
743
|
|
|
699
744
|
### The hand
|
|
700
745
|
|
|
@@ -714,17 +759,23 @@ npx nervur houses list
|
|
|
714
759
|
```
|
|
715
760
|
|
|
716
761
|
`ask` asks a being in a house as `root`: the steward, or the being
|
|
717
|
-
`--id` names. The owner
|
|
718
|
-
|
|
762
|
+
`--id` names. The owner opens an order through the steward, and hands a
|
|
763
|
+
courier's paper to it the same way. The steward's `hire` carries the
|
|
764
|
+
paper unopened, and the order takes it.
|
|
719
765
|
|
|
720
766
|
```bash
|
|
721
767
|
npx nervur ask shop open id=first
|
|
722
768
|
```
|
|
723
769
|
|
|
724
770
|
```bash
|
|
725
|
-
npx nervur ask shop
|
|
771
|
+
npx nervur ask shop hire order=first courier=7b22…
|
|
726
772
|
```
|
|
727
773
|
|
|
774
|
+
`--id` names the being asked in the steward's place, as `npx nervur ask
|
|
775
|
+
shop --id first` shows the order's describe. `--cells` reads her cells
|
|
776
|
+
and asks nothing, as `npx nervur ask shop --id first --cells`. No one
|
|
777
|
+
but the owner reads them, and only her own asks write them.
|
|
778
|
+
|
|
728
779
|
Each prints one JSON value. It exits 0 on a result and 1 on an error
|
|
729
780
|
answered. It exits 2 where nothing was asked, so a script tells a
|
|
730
781
|
refusal from a ground that is down. The hand is `state/hand` in the
|
|
@@ -750,7 +801,7 @@ with `loginctl enable-linger`. On macOS, the agent goes to
|
|
|
750
801
|
|
|
751
802
|
### In a page
|
|
752
803
|
|
|
753
|
-
`BrowserGround.open({
|
|
804
|
+
`BrowserGround.open({ registry })` from `nervur/browser` runs the same
|
|
754
805
|
houses in a page. Every tab and the service worker of one origin share
|
|
755
806
|
one ground: the one holding the Web Lock runs it, and the others reach
|
|
756
807
|
its hand over a `BroadcastChannel`. When it closes, the next opens the
|
|
@@ -758,12 +809,12 @@ ground from the same storage. `hand` answers the same three requests
|
|
|
758
809
|
the command sends: `describe`, a faculty's method, and an ask of a being
|
|
759
810
|
in a named house.
|
|
760
811
|
|
|
761
|
-
Its bodies are the browser's.
|
|
762
|
-
IndexedDB holds unextractable, and memory is IndexedDB
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
812
|
+
Its bodies are the browser's. The ground's key is sealed under an AES
|
|
813
|
+
key that IndexedDB holds unextractable, and its memory is IndexedDB.
|
|
814
|
+
Classes load from the page's own origin through the `origin` body, `{
|
|
815
|
+
body: 'origin', at: '/house/index.js' }`, and a path off the origin is
|
|
816
|
+
refused. The registry is the object you pass: makers of faculties, and
|
|
817
|
+
of any custom body, beside the terrain's own.
|
|
767
818
|
|
|
768
819
|
Any script on the origin can use the ground's keys, so the ground is
|
|
769
820
|
whoever serves the origin's script. Give it an origin of its own, serve
|
|
@@ -787,10 +838,10 @@ app's web view, on two interfaces the shell fills in native code:
|
|
|
787
838
|
which lands every write only where each key in `expect` still holds
|
|
788
839
|
what it names, and answers whether it landed.
|
|
789
840
|
|
|
790
|
-
The library holds the rest.
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
841
|
+
The library holds the rest. The ground's key goes into the secret store,
|
|
842
|
+
and its memory into the native store, which the system never evicts as
|
|
843
|
+
it may a web view's storage. A push token reaches the ground through a
|
|
844
|
+
faculty your registry makes.
|
|
794
845
|
|
|
795
846
|
## What the house guarantees
|
|
796
847
|
|
|
@@ -812,3 +863,43 @@ through a faculty your recipe makes.
|
|
|
812
863
|
leaves her absent, and the refusal says why.
|
|
813
864
|
|
|
814
865
|
A failed ask changed nothing she owns, so asking again is safe.
|
|
866
|
+
|
|
867
|
+
## What the house refuses
|
|
868
|
+
|
|
869
|
+
Each refusal answers why, where it is met: at her class's first resolve,
|
|
870
|
+
at her call, or where an ask arrives.
|
|
871
|
+
|
|
872
|
+
- A being reaching anything her position, her needs and `this.house` do
|
|
873
|
+
not give.
|
|
874
|
+
- A ground's own references handed to a being, or offered to her as a
|
|
875
|
+
faculty.
|
|
876
|
+
- A handle or an invitation in her cells.
|
|
877
|
+
- Her cells read by anyone but the owner's hand.
|
|
878
|
+
- A standing she mints herself. Standings arrive from the house.
|
|
879
|
+
- A far standing asked in the ask that took it. She asks it from her next
|
|
880
|
+
ask.
|
|
881
|
+
- A write by anyone else to her notes, and by her to her steward's.
|
|
882
|
+
- An occupant id the house reserves, and one she already holds.
|
|
883
|
+
- Two member names that clash.
|
|
884
|
+
- An ask with no entry.
|
|
885
|
+
- A state no ask reaches, an ask no role reaches, and a role unused.
|
|
886
|
+
- A method landing in a state its `to` does not name.
|
|
887
|
+
- A `readOnly` ask that writes.
|
|
888
|
+
- A need and an offer that disagree on `idempotent`.
|
|
889
|
+
- A schema keyword outside the subset `s` writes.
|
|
890
|
+
- Two offers covering one need for one kind, and a kind two sources
|
|
891
|
+
claim.
|
|
892
|
+
- An effect sent before its ask landed, or sent again while a call for
|
|
893
|
+
it is pending.
|
|
894
|
+
- An ask a stranger reaches that is not idempotent.
|
|
895
|
+
- An invite from a public being.
|
|
896
|
+
- A seed inside the house, and a seed that is not sixty-four hex digits.
|
|
897
|
+
- A memory opened with keys that derive another bound.
|
|
898
|
+
- A send to a private address, unless its ground allows it.
|
|
899
|
+
- A call on the house beside `House.open`, `door` and `ask`.
|
|
900
|
+
- A faculty in a house's code. Faculties are the ground's.
|
|
901
|
+
- A drawer opened with a key that did not seal it.
|
|
902
|
+
- A secret read by a being, a describe or anyone but a maker its entry
|
|
903
|
+
names.
|
|
904
|
+
- A faculty entry for `secrets` or `moves`, which the hand alone reaches.
|
|
905
|
+
- A ground an owner must write. Each terrain's ships.
|
package/COMMAND.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# The command
|
|
2
|
+
|
|
3
|
+
`nervur` is the command the package installs. It holds no business of
|
|
4
|
+
its own. Two words start things on your machine, and every other word is
|
|
5
|
+
read from what the running ground says it holds. This guide assumes you
|
|
6
|
+
have read [the package's start](README.md), which runs a first ground.
|
|
7
|
+
|
|
8
|
+
## Starting a ground
|
|
9
|
+
|
|
10
|
+
`nervur up` runs a NodeGround on a folder until it is stopped. The
|
|
11
|
+
folder holds your code: a folder for each house, and each module or
|
|
12
|
+
program your entries name. `state/` holds the ground's key, its ledger
|
|
13
|
+
and its hand. The key is drawn on the first start, into a file your user
|
|
14
|
+
alone reads.
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx nervur up .
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The ground stops cleanly on an interrupt and on `SIGTERM`. It takes a
|
|
21
|
+
lock on its state, so a second `nervur up` on the same folder refuses to
|
|
22
|
+
start. Keep `state/` as you keep an ssh key: whoever holds its key and
|
|
23
|
+
its ledger holds the ground, and without the key the ledger opens
|
|
24
|
+
nothing.
|
|
25
|
+
|
|
26
|
+
`nervur service` prints what keeps the ground running across reboots: a
|
|
27
|
+
systemd unit on Linux, a launchd job on macOS. Nothing is installed; you
|
|
28
|
+
place what it prints.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx nervur service /srv/shop
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Settings
|
|
35
|
+
|
|
36
|
+
A ground reads its settings from the environment.
|
|
37
|
+
|
|
38
|
+
| Setting | What it sets |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| `NERVUR_STATE` | the state folder, `state/` in the ground's folder where unset |
|
|
41
|
+
| `NERVUR_TCP_PORT` | the TCP port Quo listens on, 9110 where unset |
|
|
42
|
+
| `NERVUR_HTTP_PORT` | the port of the web listener, which faces and Quo over the web share; none where unset |
|
|
43
|
+
| `NERVUR_BIND` | the address both listen on, every interface where unset |
|
|
44
|
+
| `NERVUR_ADDRESSES` | the public addresses written into invitations, by commas |
|
|
45
|
+
| `NERVUR_ORIGINS` | the page origins the web listener answers, by commas |
|
|
46
|
+
| `NERVUR_ALLOW_PRIVATE` | `1` to let the ground dial a private or loopback address |
|
|
47
|
+
| `NERVUR_UNLOCK` | on macOS, `keychain:<account>` keeps the key in the keychain in place of `state/key` |
|
|
48
|
+
| `NERVUR_HAND` | where the hand's socket is, `state/hand` where unset; a relative path is read from where the command runs |
|
|
49
|
+
| `NERVUR_WAIT` | the longest any ask may run, in milliseconds |
|
|
50
|
+
|
|
51
|
+
A ground that people reach names its public addresses. Without them, it
|
|
52
|
+
writes only the addresses it listens on, which a stranger cannot reach.
|
|
53
|
+
|
|
54
|
+
A socket's path fits 103 bytes on macOS and 107 on Linux, and a longer
|
|
55
|
+
one refuses to start by name. A ground in a deep folder names a shorter
|
|
56
|
+
path in `NERVUR_HAND`, such as `state/hand` run from the folder, and every
|
|
57
|
+
command that reaches it names the same.
|
|
58
|
+
|
|
59
|
+
## Asking the ground
|
|
60
|
+
|
|
61
|
+
Every other word goes to the ground's hand, a socket in `state/` that
|
|
62
|
+
your user alone may open. Run the command in the ground's folder, or
|
|
63
|
+
name the socket with `--at <socket>` or `NERVUR_HAND`.
|
|
64
|
+
|
|
65
|
+
`help` prints what the ground holds: each faculty with its methods, or
|
|
66
|
+
why it is down, and each house.
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npx nervur help
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
A faculty is called by its name and a method. Named alone, it prints its
|
|
73
|
+
methods. Four faculties are the ground's own. `secrets` keeps a secret
|
|
74
|
+
in the ground's sealed drawer. `faculties` stands a faculty on the maker
|
|
75
|
+
its entry names, and `houses` opens a house on its entry.
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npx nervur faculties add name=recipe make=module args='{"at":"recipe.ts"}'
|
|
79
|
+
npx nervur faculties add name=payments from=recipe make=payments secrets='["stripe-key"]'
|
|
80
|
+
npx nervur houses add name=main classes='{"body":"folder","at":"house"}' faculties='["payments"]'
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`ask` asks a being of a house, as the house's owner. `--id <being>` names
|
|
84
|
+
her, and with none it asks the steward. With no method, it prints what
|
|
85
|
+
she shows.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npx nervur ask main
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`--cells` reads a being's cells as they last landed, and asks nothing.
|
|
92
|
+
Nothing but the hand reads cells, which makes it the tool for a test, a
|
|
93
|
+
repair, or a look at what her asks do not show.
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npx nervur ask main --cells
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The command asks no watch. A watch is held by a being on her standing,
|
|
100
|
+
or by a page through a face, where something waits on its answer.
|
|
101
|
+
|
|
102
|
+
## Arguments and answers
|
|
103
|
+
|
|
104
|
+
Arguments are one JSON object, or words `key=value`. A value is read as
|
|
105
|
+
JSON where it reads as JSON, and as text where it does not, so
|
|
106
|
+
`count=3` is a number and `name=Ada` is text.
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
npx nervur ask main hello '{"name":"Ada"}'
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
A lone `-` reads the one JSON object from standard input instead. So a
|
|
113
|
+
secret never stands on a command line or in a shell's history.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
npx nervur secrets set - < stripe-key.json
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Each word prints one JSON value, the answer, and its exit code says what
|
|
120
|
+
came back.
|
|
121
|
+
|
|
122
|
+
| Exit | What it means |
|
|
123
|
+
| --- | --- |
|
|
124
|
+
| 0 | a result, or what she shows |
|
|
125
|
+
| 1 | an error the ground or the being answered |
|
|
126
|
+
| 2 | nothing was asked: a word the command does not know, or a hand that does not answer |
|
|
127
|
+
|
|
128
|
+
So a script tells a refusal from a ground that is down.
|