@nervur-org/dock 0.4.1 → 0.6.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/README.md +17 -15
- package/api/route.ts +4 -72
- package/beings/avatar.ts +11 -7
- package/beings/carry.ts +129 -116
- package/beings/clock.ts +11 -7
- package/beings/desk.ts +7 -6
- package/beings/doorbell.ts +36 -7
- package/beings/index.ts +17 -4
- package/beings/join.ts +7 -4
- package/beings/link.ts +1 -1
- package/beings/porter.ts +5 -1
- package/beings/presence.ts +15 -5
- package/beings/setup.ts +27 -21
- package/beings/user.ts +26 -17
- package/beings/way.ts +1 -1
- package/{dock → box}/agents.ts +37 -44
- package/{dock → box}/apns.ts +4 -4
- package/box/box.ts +31 -0
- package/box/contract.ts +41 -0
- package/box/dialers.ts +88 -0
- package/box/dock.ts +148 -0
- package/box/envoy.ts +96 -0
- package/box/faculty.ts +111 -0
- package/{dock → box}/fcm.ts +1 -1
- package/box/grants.ts +90 -0
- package/box/http.ts +93 -0
- package/{dock → box}/http2.ts +7 -7
- package/box/index.ts +201 -0
- package/box/join.ts +78 -0
- package/box/local.ts +37 -0
- package/{dock → box}/location.ts +15 -3
- package/{dock → box}/notifications.ts +17 -5
- package/box/push.ts +85 -0
- package/box/ring.ts +85 -0
- package/{dock → box}/service.ts +2 -2
- package/box/timer.ts +150 -0
- package/box/tree.ts +22 -0
- package/{dock → box}/webpush.ts +2 -2
- package/cli/client.ts +1 -1
- package/cli/daemon.ts +101 -103
- package/cli/estate.ts +2 -3
- package/cli/nervur.ts +44 -25
- package/cli/stand.ts +1 -1
- package/dist/api/route.d.ts +1 -2
- package/dist/api/route.js +4 -76
- package/dist/beings/avatar.d.ts +4 -3
- package/dist/beings/avatar.js +9 -6
- package/dist/beings/carry.d.ts +10 -12
- package/dist/beings/carry.js +119 -127
- package/dist/beings/clock.js +10 -7
- package/dist/beings/desk.js +8 -7
- package/dist/beings/doorbell.d.ts +3 -1
- package/dist/beings/doorbell.js +37 -4
- package/dist/beings/index.d.ts +24 -4
- package/dist/beings/index.js +15 -4
- package/dist/beings/join.d.ts +1 -0
- package/dist/beings/join.js +6 -4
- package/dist/beings/link.d.ts +0 -1
- package/dist/beings/link.js +1 -1
- package/dist/beings/porter.js +5 -1
- package/dist/beings/presence.d.ts +1 -0
- package/dist/beings/presence.js +12 -3
- package/dist/beings/setup.d.ts +5 -2
- package/dist/beings/setup.js +16 -15
- package/dist/beings/user.d.ts +4 -3
- package/dist/beings/user.js +18 -11
- package/dist/{dock → box}/agents.d.ts +7 -4
- package/dist/{dock → box}/agents.js +30 -37
- package/dist/{dock → box}/apns.d.ts +1 -1
- package/dist/{dock → box}/apns.js +3 -3
- package/dist/box/box.d.ts +9 -0
- package/dist/box/box.js +18 -0
- package/dist/box/contract.d.ts +6 -0
- package/dist/box/contract.js +35 -0
- package/dist/{dock → box}/dialers.d.ts +7 -4
- package/dist/box/dialers.js +76 -0
- package/dist/box/dock.d.ts +182 -0
- package/dist/box/dock.js +128 -0
- package/dist/box/envoy.d.ts +44 -0
- package/dist/box/envoy.js +75 -0
- package/dist/box/faculty.d.ts +68 -0
- package/dist/box/faculty.js +97 -0
- package/dist/{dock → box}/fcm.d.ts +1 -1
- package/dist/{dock → box}/grants.d.ts +4 -3
- package/dist/box/grants.js +78 -0
- package/dist/box/http.d.ts +26 -0
- package/dist/box/http.js +89 -0
- package/dist/{dock → box}/http2.d.ts +1 -1
- package/dist/{dock → box}/http2.js +6 -6
- package/dist/box/index.d.ts +46 -0
- package/dist/box/index.js +179 -0
- package/dist/box/join.d.ts +19 -0
- package/dist/box/join.js +67 -0
- package/dist/{dock → box}/local.d.ts +3 -2
- package/dist/box/local.js +27 -0
- package/dist/{dock → box}/location.d.ts +3 -0
- package/dist/box/location.js +21 -0
- package/dist/{dock → box}/notifications.d.ts +3 -0
- package/dist/{dock → box}/notifications.js +14 -4
- package/dist/{dock → box}/push.d.ts +12 -18
- package/dist/box/push.js +83 -0
- package/dist/box/ring.d.ts +18 -0
- package/dist/box/ring.js +55 -0
- package/dist/{dock → box}/service.d.ts +1 -1
- package/dist/{dock → box}/service.js +1 -1
- package/dist/{dock → box}/timer.d.ts +2 -0
- package/dist/box/timer.js +127 -0
- package/dist/box/tree.d.ts +5 -0
- package/dist/box/tree.js +14 -0
- package/dist/{dock → box}/webpush.d.ts +1 -1
- package/dist/cli/client.d.ts +1 -0
- package/dist/cli/daemon.d.ts +2 -8
- package/dist/cli/daemon.js +102 -107
- package/dist/cli/estate.js +2 -3
- package/dist/cli/nervur.js +44 -24
- package/dist/cli/stand.d.ts +0 -14
- package/dist/cli/stand.js +1 -1
- package/dist/harbor/browser.d.ts +8 -5
- package/dist/harbor/browser.js +20 -21
- package/dist/harbor/capacitor.d.ts +3 -3
- package/dist/harbor/capacitor.js +9 -8
- package/dist/harbor/disk.d.ts +9 -9
- package/dist/harbor/disk.js +56 -51
- package/dist/harbor/edge/alarm.d.ts +4 -2
- package/dist/harbor/edge/alarm.js +9 -19
- package/dist/harbor/edge/edge.d.ts +7 -6
- package/dist/harbor/edge/edge.js +58 -53
- package/dist/harbor/edge/exercise.js +4 -4
- package/dist/harbor/edge/given.d.ts +0 -1
- package/dist/harbor/edge/given.js +0 -29
- package/dist/harbor/edge/storage.d.ts +0 -2
- package/dist/harbor/edge/storage.js +2 -2
- package/dist/harbor/http.js +4 -2
- package/dist/harbor/sealed.d.ts +0 -5
- package/dist/harbor/sealed.js +0 -39
- package/dist/harbor/tauri.d.ts +2 -2
- package/dist/harbor/tauri.js +13 -10
- package/dist/human/app.d.ts +1 -1
- package/dist/human/app.js +10 -12
- package/dist/human/door.d.ts +0 -1
- package/dist/human/door.js +1 -1
- package/dist/human/html.js +1 -1
- package/dist/human/move.js +1 -1
- package/dist/human/tab.bundle.txt +3629 -2824
- package/dist/human/wake.d.ts +5 -2
- package/dist/human/wake.js +23 -14
- package/dist/human/web.d.ts +0 -1
- package/dist/human/web.js +3 -3
- package/dist/human/worker.bundle.txt +2945 -2118
- package/dist/human/worlds.js +3 -3
- package/dist/mcp/agent.d.ts +0 -1
- package/dist/mcp/agent.js +1 -1
- package/dist/mcp/allow.js +3 -2
- package/dist/mcp/http.d.ts +0 -1
- package/dist/mcp/http.js +1 -1
- package/dist/mcp/oauth.d.ts +3 -4
- package/dist/mcp/oauth.js +4 -4
- package/dist/mcp/route.d.ts +1 -1
- package/dist/mcp/runner.d.ts +0 -1
- package/dist/mcp/runner.js +1 -1
- package/dist/mcp/server.d.ts +0 -1
- package/dist/mcp/server.js +1 -1
- package/harbor/browser.ts +22 -24
- package/harbor/capacitor.ts +9 -8
- package/harbor/disk.ts +53 -48
- package/harbor/edge/alarm.ts +15 -12
- package/harbor/edge/edge.ts +61 -55
- package/harbor/edge/exercise.ts +4 -4
- package/harbor/edge/given.ts +3 -33
- package/harbor/edge/storage.ts +2 -2
- package/harbor/http.ts +5 -3
- package/harbor/sealed.ts +0 -35
- package/harbor/tauri.ts +13 -10
- package/human/app.ts +12 -13
- package/human/door.ts +1 -1
- package/human/html.ts +1 -1
- package/human/local.ts +1 -1
- package/human/move.ts +1 -1
- package/human/tab.bundle.txt +3629 -2824
- package/human/wake.ts +36 -16
- package/human/web.ts +4 -4
- package/human/worker.bundle.txt +2945 -2118
- package/human/worlds.ts +3 -3
- package/mcp/agent.ts +1 -1
- package/mcp/allow.ts +2 -1
- package/mcp/http.ts +1 -1
- package/mcp/oauth.ts +4 -4
- package/mcp/route.ts +1 -1
- package/mcp/runner.ts +1 -1
- package/mcp/server.ts +1 -1
- package/package.json +10 -18
- package/GETTING_STARTED.md +0 -138
- package/GLOSSARY.md +0 -118
- package/WORLDS.md +0 -569
- package/beings/envoy.ts +0 -218
- package/dist/beings/envoy.d.ts +0 -54
- package/dist/beings/envoy.js +0 -211
- package/dist/dock/console.d.ts +0 -6
- package/dist/dock/console.js +0 -20
- package/dist/dock/dialers.js +0 -75
- package/dist/dock/faculty.d.ts +0 -24
- package/dist/dock/faculty.js +0 -142
- package/dist/dock/grants.js +0 -99
- package/dist/dock/index.d.ts +0 -41
- package/dist/dock/index.js +0 -113
- package/dist/dock/local.js +0 -44
- package/dist/dock/location.js +0 -11
- package/dist/dock/push.js +0 -132
- package/dist/dock/timer.js +0 -149
- package/dock/console.ts +0 -23
- package/dock/dialers.ts +0 -85
- package/dock/faculty.ts +0 -148
- package/dock/grants.ts +0 -111
- package/dock/index.ts +0 -133
- package/dock/local.ts +0 -48
- package/dock/push.ts +0 -161
- package/dock/timer.ts +0 -174
- package/quo-api.md +0 -196
- package/quo-app-bells.md +0 -280
- package/quo-dock.md +0 -1945
- package/quo-harbor.md +0 -874
- package/quo-human.md +0 -1042
- package/quo-mcp.md +0 -343
- /package/dist/{dock → box}/fcm.js +0 -0
- /package/dist/{dock → box}/webpush.js +0 -0
package/dist/beings/carry.js
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
-
//
|
|
3
|
-
//
|
|
2
|
+
// Carrying: a being shows the asks of the standings she holds as asks of
|
|
3
|
+
// her own, and forwards. Whoever she carries for sees, in one describe,
|
|
4
4
|
// what she can be asked and what every being she holds can be asked, each
|
|
5
5
|
// under that standing's name; asking one is an ask on that standing, in her
|
|
6
6
|
// name, so the far being sees her and never who is behind her. A user being
|
|
7
|
-
// carries
|
|
8
|
-
//
|
|
7
|
+
// carries her org for the human's devices; a presence being carries her
|
|
8
|
+
// device's faculties to her world; the Dock carries the box's faculties to
|
|
9
|
+
// a screen. Nothing here knows what she is.
|
|
10
|
+
//
|
|
11
|
+
// It is composed and never extended: carrying is something a being does,
|
|
12
|
+
// not what she is, so a being on any rung of the kit's ladder carries by
|
|
13
|
+
// answering through `carry` and saying her rules as statics of her class.
|
|
14
|
+
// The four rules have a default each, and a class says only the ones she
|
|
15
|
+
// means to change.
|
|
9
16
|
//
|
|
10
17
|
// A carried ask is `<id>-<name>`, and the mapping back is kept in her cells
|
|
11
18
|
// and never parsed from the name, so an id with a dash in it is no trouble.
|
|
@@ -18,8 +25,21 @@
|
|
|
18
25
|
// `look` once per digest, and keeps both in her cells. So a describe of
|
|
19
26
|
// hers may cost one ask per stale standing, which is the price of a page
|
|
20
27
|
// that is never more than one ask behind.
|
|
21
|
-
import {
|
|
28
|
+
import { isSilence, isWord, wordOf } from 'nervur';
|
|
22
29
|
import { sanitise } from './look.js';
|
|
30
|
+
export const CARRIES = {
|
|
31
|
+
carries: () => false,
|
|
32
|
+
hidden: (id) => id.startsWith('to:'),
|
|
33
|
+
skips: () => false,
|
|
34
|
+
shows: () => true,
|
|
35
|
+
};
|
|
36
|
+
// Her rules, read off her class; one she left unsaid is the default.
|
|
37
|
+
function rulesOf(self) {
|
|
38
|
+
const C = self.constructor;
|
|
39
|
+
return { carries: C.carries ?? CARRIES.carries, hidden: C.hidden ?? CARRIES.hidden, skips: C.skips ?? CARRIES.skips, shows: C.shows ?? CARRIES.shows };
|
|
40
|
+
}
|
|
41
|
+
const carriedOf = (self) => (self.cells.carried ??= {});
|
|
42
|
+
const looksOf = (self) => (self.cells.looks ??= {});
|
|
23
43
|
// The names a far being carries, read off her notes: every ask her
|
|
24
44
|
// `standings` groups name, and each group's page. Empty when she carries
|
|
25
45
|
// nothing, which a bare avatar does not.
|
|
@@ -39,136 +59,108 @@ function carriedBy(bp) {
|
|
|
39
59
|
}
|
|
40
60
|
return out;
|
|
41
61
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
//
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
//
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
// the same way, and her digest with it. The digest is how everyone
|
|
91
|
-
// holding a standing on her learns she changed, so a shape that follows
|
|
92
|
-
// history says she changed when nothing about her did, and a watcher
|
|
93
|
-
// refreshes or walks away over the order two lends came back in.
|
|
94
|
-
for (const [id, rec] of [...Object.entries(this.cells.standings)].sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))) {
|
|
95
|
-
if (C.skips(id))
|
|
96
|
-
continue;
|
|
97
|
-
const st = this.standings[id];
|
|
98
|
-
if (!st)
|
|
62
|
+
// Her describe with her standings carried into it, for an asker who may
|
|
63
|
+
// see them. Every other asker gets her describe alone.
|
|
64
|
+
export async function blueprint(self, asker) {
|
|
65
|
+
const rules = rulesOf(self);
|
|
66
|
+
const bp = self.describe(asker);
|
|
67
|
+
const occ = self.occupant(asker);
|
|
68
|
+
if (!rules.carries(occ, asker))
|
|
69
|
+
return bp;
|
|
70
|
+
const own = new Set(bp.asks.map((a) => a.name));
|
|
71
|
+
const carried = {};
|
|
72
|
+
const groups = {};
|
|
73
|
+
const looks = looksOf(self);
|
|
74
|
+
// By id, and never in the order she happened to take them. Her cells keep
|
|
75
|
+
// standings in the order they were taken, which is the order a lend
|
|
76
|
+
// answered, a device came back or a relation was dropped and taken again:
|
|
77
|
+
// history, and no fact about her. Carried into her blueprint in that
|
|
78
|
+
// order, her shape would come out differently on two runs that made her
|
|
79
|
+
// the same way, and her digest with it. The digest is how everyone
|
|
80
|
+
// holding a standing on her learns she changed, so a shape that follows
|
|
81
|
+
// history says she changed when nothing about her did, and a watcher
|
|
82
|
+
// refreshes or walks away over the order two lends came back in.
|
|
83
|
+
for (const [id, rec] of [...Object.entries(self.cells.standings)].sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))) {
|
|
84
|
+
if (rules.skips(id))
|
|
85
|
+
continue;
|
|
86
|
+
const st = self.standings[id];
|
|
87
|
+
if (!st)
|
|
88
|
+
continue;
|
|
89
|
+
if (!rec.blueprint || rec.seen !== rec.digest)
|
|
90
|
+
await st.ask(); // her ward writes the record
|
|
91
|
+
if (!rec.blueprint)
|
|
92
|
+
continue;
|
|
93
|
+
// plumbing carries what it carries and nothing of its own: the names
|
|
94
|
+
// the far being's notes group under her standings, or none
|
|
95
|
+
const through = rules.hidden(id) ? carriedBy(rec.blueprint) : null;
|
|
96
|
+
if (through && through.size === 0)
|
|
97
|
+
continue;
|
|
98
|
+
// The mapping is written for every standing she carries, whoever is
|
|
99
|
+
// asking: it is one map in her cells, and the last describe must not
|
|
100
|
+
// decide what the next asker may call. Who sees a standing is decided
|
|
101
|
+
// here and again at answer, by `shows`.
|
|
102
|
+
const shown = rules.shows(id, occ, asker);
|
|
103
|
+
// her look is kept here once per digest and never carried as an ask;
|
|
104
|
+
// her page follows every call, so it is carried as one and named in
|
|
105
|
+
// the notes, where every side finds it and none takes it for a form
|
|
106
|
+
const names = [];
|
|
107
|
+
const group = { asks: names };
|
|
108
|
+
for (const a of rec.blueprint.asks) {
|
|
109
|
+
if (a.name === 'look')
|
|
99
110
|
continue;
|
|
100
|
-
if (
|
|
101
|
-
await st.ask(); // her ward writes the record
|
|
102
|
-
if (!rec.blueprint)
|
|
111
|
+
if (through && !through.has(a.name))
|
|
103
112
|
continue;
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const through = C.hidden(id) ? carriedBy(rec.blueprint) : null;
|
|
107
|
-
if (through && through.size === 0)
|
|
113
|
+
const name = `${id}-${a.name}`;
|
|
114
|
+
if (own.has(name))
|
|
108
115
|
continue;
|
|
109
|
-
|
|
110
|
-
// asking: it is one map in her cells, and the last describe must not
|
|
111
|
-
// decide what the next asker may call. Who sees a standing is decided
|
|
112
|
-
// here and again at answer, by `shows`.
|
|
113
|
-
const shown = C.shows(id, occ, asker);
|
|
114
|
-
// her look is kept here once per digest and never carried as an ask;
|
|
115
|
-
// her page follows every call, so it is carried as one and named in
|
|
116
|
-
// the notes, where every side finds it and none takes it for a form
|
|
117
|
-
const names = [];
|
|
118
|
-
const group = { asks: names };
|
|
119
|
-
for (const a of rec.blueprint.asks) {
|
|
120
|
-
if (a.name === 'look')
|
|
121
|
-
continue;
|
|
122
|
-
if (through && !through.has(a.name))
|
|
123
|
-
continue;
|
|
124
|
-
const name = `${id}-${a.name}`;
|
|
125
|
-
if (own.has(name))
|
|
126
|
-
continue;
|
|
127
|
-
carried[name] = { id, ask: a.name };
|
|
128
|
-
if (!shown)
|
|
129
|
-
continue;
|
|
130
|
-
bp.asks.push({ ...a, name });
|
|
131
|
-
if (a.name === 'page')
|
|
132
|
-
group.page = name;
|
|
133
|
-
else
|
|
134
|
-
names.push(name);
|
|
135
|
-
}
|
|
116
|
+
carried[name] = { id, ask: a.name };
|
|
136
117
|
if (!shown)
|
|
137
118
|
continue;
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
119
|
+
bp.asks.push({ ...a, name });
|
|
120
|
+
if (a.name === 'page')
|
|
121
|
+
group.page = name;
|
|
122
|
+
else
|
|
123
|
+
names.push(name);
|
|
124
|
+
}
|
|
125
|
+
if (!shown)
|
|
126
|
+
continue;
|
|
127
|
+
if (rec.blueprint.asks.some((a) => a.name === 'look')) {
|
|
128
|
+
const kept = looks[id];
|
|
129
|
+
if (!kept || kept.digest !== rec.digest) {
|
|
130
|
+
const l = await st.ask('look');
|
|
131
|
+
looks[id] = { digest: rec.digest, look: isSilence(l) || isWord(l) ? {} : sanitise(l) };
|
|
145
132
|
}
|
|
146
|
-
|
|
133
|
+
group.look = looks[id].look;
|
|
147
134
|
}
|
|
148
|
-
|
|
149
|
-
if (!(id in groups))
|
|
150
|
-
delete this.looks[id];
|
|
151
|
-
this.cells.carried = carried;
|
|
152
|
-
const notes = bp.notes !== null && typeof bp.notes === 'object' && !Array.isArray(bp.notes) ? bp.notes : {};
|
|
153
|
-
return { asks: bp.asks, notes: { ...notes, standings: groups } };
|
|
135
|
+
groups[id] = group;
|
|
154
136
|
}
|
|
155
|
-
|
|
156
|
-
if (
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
137
|
+
for (const id of Object.keys(looks))
|
|
138
|
+
if (!(id in groups))
|
|
139
|
+
delete looks[id];
|
|
140
|
+
self.cells.carried = carried;
|
|
141
|
+
const notes = bp.notes !== null && typeof bp.notes === 'object' && !Array.isArray(bp.notes) ? bp.notes : {};
|
|
142
|
+
return { asks: bp.asks, notes: { ...notes, standings: groups } };
|
|
143
|
+
}
|
|
144
|
+
// Her answer, carrying: the empty ask is her carried blueprint, a carried
|
|
145
|
+
// name is an ask on that standing in her name, and everything else is her
|
|
146
|
+
// own, which the class hands in as `own`.
|
|
147
|
+
export async function carry(self, asker, method, args, own) {
|
|
148
|
+
if (method === undefined)
|
|
149
|
+
return blueprint(self, asker);
|
|
150
|
+
const rules = rulesOf(self);
|
|
151
|
+
const carried = carriedOf(self);
|
|
152
|
+
const to = Object.hasOwn(carried, method) ? carried[method] : undefined;
|
|
153
|
+
const occ = self.occupant(asker);
|
|
154
|
+
if (to && rules.carries(occ, asker) && rules.shows(to.id, occ, asker)) {
|
|
155
|
+
const st = self.standings[to.id];
|
|
156
|
+
if (!st)
|
|
157
|
+
return { error: 'unknown ask' };
|
|
158
|
+
const out = await st.ask(to.ask, args);
|
|
159
|
+
if (isSilence(out))
|
|
170
160
|
return out;
|
|
171
|
-
|
|
172
|
-
|
|
161
|
+
if (isWord(out))
|
|
162
|
+
return { error: wordOf(out) };
|
|
163
|
+
return out;
|
|
173
164
|
}
|
|
165
|
+
return own(asker, method, args);
|
|
174
166
|
}
|
package/dist/beings/clock.js
CHANGED
|
@@ -30,7 +30,10 @@
|
|
|
30
30
|
// from a file and nothing is set on the class, so a schedule outlives the
|
|
31
31
|
// process the way every cell does, and is gone when it is dropped.
|
|
32
32
|
import { Being, isSilence, isWord, wordOf, OWNER } from 'nervur';
|
|
33
|
-
import { TIMER
|
|
33
|
+
import { TIMER as TIMING } from '../box/timer.js';
|
|
34
|
+
import { join } from '../box/join.js';
|
|
35
|
+
// Her standing at the box's timer, under an id of her own.
|
|
36
|
+
const TIMER = 'timer';
|
|
34
37
|
// The root and nobody else. `OWNER` is one of the ward's own words, refused at
|
|
35
38
|
// every mint, so no occupant can ever wear it: an ask gated this way is the
|
|
36
39
|
// device's own and cannot be reached through a door.
|
|
@@ -286,7 +289,7 @@ export class Clock extends Being {
|
|
|
286
289
|
joined;
|
|
287
290
|
constructor(stance) {
|
|
288
291
|
super(stance);
|
|
289
|
-
this.joined = join(this, TIMER, { method: 'tick' });
|
|
292
|
+
this.joined = join(this, TIMING, TIMER, { method: 'tick' });
|
|
290
293
|
}
|
|
291
294
|
static asks = {
|
|
292
295
|
tick: { description: 'fire everything due at this moment, and answer the tally and when she is next due', input: NOW, for: timer },
|
|
@@ -351,9 +354,9 @@ export class Clock extends Being {
|
|
|
351
354
|
async told() {
|
|
352
355
|
if (!Object.hasOwn(this.cells.standings, TIMER))
|
|
353
356
|
return;
|
|
354
|
-
const
|
|
355
|
-
const
|
|
356
|
-
const now =
|
|
357
|
+
const hers = this.standings[TIMER];
|
|
358
|
+
const heard = await hers?.ask('now', {});
|
|
359
|
+
const now = heard !== null && typeof heard === 'object' ? heard.now : undefined;
|
|
357
360
|
if (typeof now !== 'number' || !Number.isFinite(now))
|
|
358
361
|
return;
|
|
359
362
|
// A schedule due at this very moment is a round now, not a round at the
|
|
@@ -361,7 +364,7 @@ export class Clock extends Being {
|
|
|
361
364
|
// and the schedule kept inside it names it.
|
|
362
365
|
const at = this.schedules().some((s) => this.#ready(s, now)) ? now : this.#soonest(floor(now));
|
|
363
366
|
if (at !== null)
|
|
364
|
-
await
|
|
367
|
+
await hers?.ask('due', { at });
|
|
365
368
|
}
|
|
366
369
|
// One list, her own cell and nothing else.
|
|
367
370
|
schedules() {
|
|
@@ -509,7 +512,7 @@ export const CLOCK = 'clock';
|
|
|
509
512
|
// because it is the same act: the owner creates and places, and the work is
|
|
510
513
|
// hers from then on.
|
|
511
514
|
export async function setupClock(hosted, wakes = []) {
|
|
512
|
-
const out = (await hosted.ask('boot', { key: CLOCK, class: 'Clock' }));
|
|
515
|
+
const out = (await hosted.ask('boot', { key: CLOCK, class: 'beings/Clock' }));
|
|
513
516
|
if (out.error)
|
|
514
517
|
throw new Error(`clock: ${out.error}`);
|
|
515
518
|
for (const being of wakes)
|
package/dist/beings/desk.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// way in turns a proof of one kind into who it is for: which user, which
|
|
9
9
|
// client identity. The ways in are beings, and the desk reaches each of
|
|
10
10
|
// them as she reaches anything, at a standing under `way:<kind>`: the
|
|
11
|
-
// world's own, placed by the root, and the box's, lent by the
|
|
11
|
+
// world's own, placed by the root, and the box's, lent by the box ward and
|
|
12
12
|
// taken at her birth, so a box with no local side offers no such kind.
|
|
13
13
|
//
|
|
14
14
|
// A kind whose proof the world has to hand out first answers `send` beside
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
// sent to before, or what a link says. She keeps the ways in named in one
|
|
18
18
|
// place, so a side that renders her renders every way into this world.
|
|
19
19
|
import { Being, isSilence, isWord, wordOf } from 'nervur';
|
|
20
|
-
import { join } from '../
|
|
21
|
-
import { LOCAL } from '../
|
|
20
|
+
import { join } from '../box/join.js';
|
|
21
|
+
import { LOCAL } from '../box/local.js';
|
|
22
22
|
import { WAY, kindOf, verified } from './way.js';
|
|
23
23
|
export class Desk extends Being {
|
|
24
24
|
static asks = {
|
|
@@ -31,7 +31,7 @@ export class Desk extends Being {
|
|
|
31
31
|
// nothing under that id and the kind is not offered.
|
|
32
32
|
constructor(stance) {
|
|
33
33
|
super(stance);
|
|
34
|
-
void join(this, LOCAL,
|
|
34
|
+
void join(this, LOCAL, WAY('local'));
|
|
35
35
|
}
|
|
36
36
|
// The ids of the ways in she holds, in the order they were placed.
|
|
37
37
|
get ways() {
|
|
@@ -116,9 +116,10 @@ export class Desk extends Being {
|
|
|
116
116
|
// key. A way in that does not say `make` reaches an existing household
|
|
117
117
|
// and nothing else, which is what the local kind on a device does.
|
|
118
118
|
if (!this.standings[id] && (who.make === true || typeof who.make === 'string')) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
119
|
+
// a key the ward already holds, her own included, is refused by the boot
|
|
120
|
+
if (!/^[\w.-]{1,80}$/.test(who.user))
|
|
121
|
+
return { error: 'a user is a word' };
|
|
122
|
+
if ((await this.boot(typeof who.make === 'string' ? who.make : 'beings/User', who.user, id)) === null)
|
|
122
123
|
return { error: 'no such user' };
|
|
123
124
|
await this.standings[id].ask('hello', { name: who.user });
|
|
124
125
|
}
|
|
@@ -4,6 +4,7 @@ declare const isDevice: (occ: OccupantRecord | undefined) => boolean;
|
|
|
4
4
|
declare const isWorld: (occ: OccupantRecord | undefined) => boolean;
|
|
5
5
|
declare const isMaker: (occ: OccupantRecord | undefined) => occ is OccupantRecord;
|
|
6
6
|
export declare class Doorbell extends Being {
|
|
7
|
+
static readonly at = "beings/Doorbell";
|
|
7
8
|
static cells: JsonObject;
|
|
8
9
|
static asks: {
|
|
9
10
|
claim: {
|
|
@@ -69,7 +70,8 @@ export declare class Doorbell extends Being {
|
|
|
69
70
|
};
|
|
70
71
|
describe(asker: Parameters<Being['describe']>[0]): import("nervur").Blueprint;
|
|
71
72
|
claim(_args: JsonObject, asker: Asker): Promise<JsonObject>;
|
|
72
|
-
keep(args: JsonObject): JsonObject
|
|
73
|
+
keep(args: JsonObject): Promise<JsonObject>;
|
|
74
|
+
private at;
|
|
73
75
|
admit(_args: JsonObject): Promise<JsonObject>;
|
|
74
76
|
drop(args: JsonObject): JsonObject;
|
|
75
77
|
allowed(_args: JsonObject): JsonObject;
|
package/dist/beings/doorbell.js
CHANGED
|
@@ -28,11 +28,17 @@ const DEVICE = 'device';
|
|
|
28
28
|
const MINE = 'push';
|
|
29
29
|
// What a platform will carry. It is the faculty's number, because the
|
|
30
30
|
// faculty is the one that hands a ring to a platform.
|
|
31
|
-
import { SEAL } from '../
|
|
31
|
+
import { SEAL, isToken } from '../box/ring.js';
|
|
32
|
+
import { PUSH } from '../box/push.js';
|
|
33
|
+
import { join } from '../box/join.js';
|
|
32
34
|
const isDevice = (occ) => occ?.id === DEVICE;
|
|
33
35
|
const isWorld = (occ) => occ !== undefined && occ.id !== DEVICE;
|
|
34
36
|
const isMaker = (occ) => occ !== undefined;
|
|
35
37
|
export class Doorbell extends Being {
|
|
38
|
+
// Where this class lives in a tree, which is her key in a ward. She says
|
|
39
|
+
// it herself, so the porter who boots her spells no path of her own and a
|
|
40
|
+
// class moved is one line moved with it.
|
|
41
|
+
static at = 'beings/Doorbell';
|
|
36
42
|
static cells = { token: null, admitted: 0, claimed: false };
|
|
37
43
|
static asks = {
|
|
38
44
|
claim: { description: 'the one way in for this doorbell, handed out once', input: { type: 'object' }, for: isMaker },
|
|
@@ -70,13 +76,40 @@ export class Doorbell extends Being {
|
|
|
70
76
|
}
|
|
71
77
|
// Written once and rewritten whenever the platform hands the phone a new
|
|
72
78
|
// one. No world is told anything, because no world was ever given it.
|
|
73
|
-
|
|
79
|
+
//
|
|
80
|
+
// A kind is one of the rings the box behind this bell holds, and a token
|
|
81
|
+
// of any other kind is refused here, at the door, with an error object.
|
|
82
|
+
// The faculty is asked which kinds it rings, because the faculty is the
|
|
83
|
+
// one that hands a ring to a platform and nothing else on this bell knows.
|
|
84
|
+
// A device told at the moment it hands a token can hand another or ask its
|
|
85
|
+
// human for a bell that can reach it; a device told nothing goes on
|
|
86
|
+
// believing it is reachable until a world rings and is refused, and by then
|
|
87
|
+
// the only one who could act is the only one not there.
|
|
88
|
+
async keep(args) {
|
|
74
89
|
const token = args.token;
|
|
75
|
-
if (
|
|
90
|
+
if (!isToken(token))
|
|
76
91
|
return { error: 'a token names its kind' };
|
|
92
|
+
const at = await this.at();
|
|
93
|
+
if (!at)
|
|
94
|
+
return { error: 'this box rings nothing' };
|
|
95
|
+
const said = await at.ask('kinds', {});
|
|
96
|
+
if (said === undefined || isSilence(said))
|
|
97
|
+
return { error: 'this box rings nothing' };
|
|
98
|
+
if (isWord(said))
|
|
99
|
+
return { error: wordOf(said) };
|
|
100
|
+
const kinds = said.kinds;
|
|
101
|
+
if (!Array.isArray(kinds))
|
|
102
|
+
return { error: 'this box rings nothing' };
|
|
103
|
+
if (!kinds.includes(token.kind))
|
|
104
|
+
return { error: `this box cannot ring a ${token.kind}` };
|
|
77
105
|
this.cells.token = token;
|
|
78
106
|
return { kept: token.kind };
|
|
79
107
|
}
|
|
108
|
+
// Her standing at the box's push faculty, taken the first time it is
|
|
109
|
+
// wanted and held from then on.
|
|
110
|
+
async at() {
|
|
111
|
+
return this.standings[MINE] ?? (await join(this, PUSH, MINE).then(() => this.standings[MINE]));
|
|
112
|
+
}
|
|
80
113
|
// The device allows a world by asking for a way in and handing it over.
|
|
81
114
|
// So a world can only ring a phone that chose it.
|
|
82
115
|
async admit(_args) {
|
|
@@ -113,7 +146,7 @@ export class Doorbell extends Being {
|
|
|
113
146
|
const token = this.cells.token;
|
|
114
147
|
if (token === null)
|
|
115
148
|
return { error: 'this device has handed no token' };
|
|
116
|
-
const at =
|
|
149
|
+
const at = await this.at();
|
|
117
150
|
if (!at)
|
|
118
151
|
return { error: 'this box rings nothing' };
|
|
119
152
|
const out = await at.ask('ring', { token, sealed });
|
package/dist/beings/index.d.ts
CHANGED
|
@@ -2,13 +2,33 @@ export { User, DESK, HOME, BELL } from './user.ts';
|
|
|
2
2
|
export { Desk } from './desk.ts';
|
|
3
3
|
export { WAY, kindOf, verified, VERIFY, SEND, type Proof, type Verified } from './way.ts';
|
|
4
4
|
export { Avatar, USER, PUSHER } from './avatar.ts';
|
|
5
|
-
export {
|
|
5
|
+
export { carry, blueprint, CARRIES, type Carrying } from './carry.ts';
|
|
6
6
|
export { Presence } from './presence.ts';
|
|
7
7
|
export { Courier, MOVER, isMoving, type Moving } from './courier.ts';
|
|
8
8
|
export { Porter } from './porter.ts';
|
|
9
9
|
export { Doorbell } from './doorbell.ts';
|
|
10
|
-
export {
|
|
11
|
-
export {
|
|
12
|
-
export { webPush, mintVapid, publicOf, apnsPush, pkcs8, HOSTS, fcmPush, isAccount, DOORS, handedTo, ringing, routed, type Vapid, type Apns, type Account, type Doors } from '../
|
|
10
|
+
export { BOX, BOX_SEED, Dock, LOCAL, LOCATION, NOTIFICATIONS, PUSH, TIMER, Faculty, Local, Location, Notifications, Push, Timer, contract, covers, nameOf, titleOf, keyed, join, settled, stand, standHarbor, classes, lent, type Contract, type Tree, type Where, type Watched, type Rooted } from '../box/index.ts';
|
|
11
|
+
export { isToken, type Ring, type Token } from '../box/index.ts';
|
|
12
|
+
export { webPush, mintVapid, publicOf, apnsPush, pkcs8, HOSTS, fcmPush, isAccount, DOORS, handedTo, ringing, routed, type Vapid, type Apns, type Account, type Doors } from '../box/index.ts';
|
|
13
13
|
export { Clock, CLOCK, setupClock, placeClock, readSchedule, parseCron, nextFire, civil, fromCivil, type Schedule, type Fire, type Cron, type Civil } from './clock.ts';
|
|
14
14
|
export { sanitise, hint, hintFor, groups, type Look, type Hint } from './look.ts';
|
|
15
|
+
import { User } from './user.ts';
|
|
16
|
+
import { Desk } from './desk.ts';
|
|
17
|
+
import { Avatar } from './avatar.ts';
|
|
18
|
+
import { Presence } from './presence.ts';
|
|
19
|
+
import { Clock } from './clock.ts';
|
|
20
|
+
import { Courier } from './courier.ts';
|
|
21
|
+
import { Porter } from './porter.ts';
|
|
22
|
+
import { Doorbell } from './doorbell.ts';
|
|
23
|
+
export declare const BEINGS: {
|
|
24
|
+
beings: {
|
|
25
|
+
User: typeof User;
|
|
26
|
+
Desk: typeof Desk;
|
|
27
|
+
Avatar: typeof Avatar;
|
|
28
|
+
Presence: typeof Presence;
|
|
29
|
+
Clock: typeof Clock;
|
|
30
|
+
Courier: typeof Courier;
|
|
31
|
+
Porter: typeof Porter;
|
|
32
|
+
Doorbell: typeof Doorbell;
|
|
33
|
+
};
|
|
34
|
+
};
|
package/dist/beings/index.js
CHANGED
|
@@ -4,13 +4,24 @@ export { User, DESK, HOME, BELL } from './user.js';
|
|
|
4
4
|
export { Desk } from './desk.js';
|
|
5
5
|
export { WAY, kindOf, verified, VERIFY, SEND } from './way.js';
|
|
6
6
|
export { Avatar, USER, PUSHER } from './avatar.js';
|
|
7
|
-
export {
|
|
7
|
+
export { carry, blueprint, CARRIES } from './carry.js';
|
|
8
8
|
export { Presence } from './presence.js';
|
|
9
9
|
export { Courier, MOVER, isMoving } from './courier.js';
|
|
10
10
|
export { Porter } from './porter.js';
|
|
11
11
|
export { Doorbell } from './doorbell.js';
|
|
12
|
-
export {
|
|
13
|
-
export {
|
|
14
|
-
export { webPush, mintVapid, publicOf, apnsPush, pkcs8, HOSTS, fcmPush, isAccount, DOORS, handedTo, ringing, routed } from '../
|
|
12
|
+
export { BOX, BOX_SEED, Dock, LOCAL, LOCATION, NOTIFICATIONS, PUSH, TIMER, Faculty, Local, Location, Notifications, Push, Timer, contract, covers, nameOf, titleOf, keyed, join, settled, stand, standHarbor, classes, lent } from '../box/index.js';
|
|
13
|
+
export { isToken } from '../box/index.js';
|
|
14
|
+
export { webPush, mintVapid, publicOf, apnsPush, pkcs8, HOSTS, fcmPush, isAccount, DOORS, handedTo, ringing, routed } from '../box/index.js';
|
|
15
15
|
export { Clock, CLOCK, setupClock, placeClock, readSchedule, parseCron, nextFire, civil, fromCivil } from './clock.js';
|
|
16
16
|
export { sanitise, hint, hintFor, groups } from './look.js';
|
|
17
|
+
import { User } from './user.js';
|
|
18
|
+
import { Desk } from './desk.js';
|
|
19
|
+
import { Avatar } from './avatar.js';
|
|
20
|
+
import { Presence } from './presence.js';
|
|
21
|
+
import { Clock } from './clock.js';
|
|
22
|
+
import { Courier } from './courier.js';
|
|
23
|
+
import { Porter } from './porter.js';
|
|
24
|
+
import { Doorbell } from './doorbell.js';
|
|
25
|
+
// The beings this folder brings to every harbor, as a tree: a ward names
|
|
26
|
+
// one by where it lives, `beings/User`, as it names a faculty.
|
|
27
|
+
export const BEINGS = { beings: { User, Desk, Avatar, Presence, Clock, Courier, Porter, Doorbell } };
|
package/dist/beings/join.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Hosted } from 'nervur/harbor';
|
|
2
2
|
import type { Invitation } from 'nervur';
|
|
3
3
|
import type { Avatar } from './avatar.ts';
|
|
4
|
+
export declare const isIdentity: (hosted: Hosted, identity: unknown) => identity is string;
|
|
4
5
|
export declare function avatarOf(hosted: Hosted, identity: string): Promise<{
|
|
5
6
|
avatar?: Avatar;
|
|
6
7
|
error?: string;
|
package/dist/beings/join.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
1
|
+
// An identity is a word, and never the key of a being the ward holds: the
|
|
2
|
+
// ward is asked, so no route names who its beings are.
|
|
3
|
+
export const isIdentity = (hosted, identity) => typeof identity === 'string' && /^[\w.-]+$/.test(identity) && !hosted.keys().includes(identity);
|
|
4
|
+
// Her avatar in a ward, found or booted under the identity's key.
|
|
3
5
|
export async function avatarOf(hosted, identity) {
|
|
4
|
-
if (
|
|
6
|
+
if (!isIdentity(hosted, identity))
|
|
5
7
|
return { error: 'an identity is a word, and not a being of the ward' };
|
|
6
8
|
const key = `avatar:${identity}`;
|
|
7
9
|
let avatar = hosted.being(key);
|
|
8
10
|
if (!avatar) {
|
|
9
|
-
const out = (await hosted.ask('boot', { key, class: 'Avatar' }));
|
|
11
|
+
const out = (await hosted.ask('boot', { key, class: 'beings/Avatar' }));
|
|
10
12
|
if (out.error)
|
|
11
13
|
return { error: out.error };
|
|
12
14
|
avatar = hosted.being(key);
|
package/dist/beings/link.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Invitation } from 'nervur';
|
|
2
2
|
export declare const KEY = "nervur";
|
|
3
|
-
export declare const PROOF = "proof";
|
|
4
3
|
export declare function format(inv: Invitation): string;
|
|
5
4
|
export declare function parse(hash: string): Invitation | null;
|
|
6
5
|
export declare function parseProof(hash: string): {
|
package/dist/beings/link.js
CHANGED
|
@@ -5,7 +5,7 @@ export const KEY = 'nervur';
|
|
|
5
5
|
// a query string is in every log and every referer, and one read of it is
|
|
6
6
|
// one way in taken. `<kind>.<token>`, the kind the desk knows it by and the
|
|
7
7
|
// token that door minted.
|
|
8
|
-
|
|
8
|
+
const PROOF = 'proof';
|
|
9
9
|
const HEX = (n) => `[0-9a-f]{${n}}`;
|
|
10
10
|
const FULL = new RegExp(`^(${HEX(128)})\\.(${HEX(64)})\\.(${HEX(64)})$`);
|
|
11
11
|
const PUBLIC = new RegExp(`^${HEX(128)}$`);
|
package/dist/beings/porter.js
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
// harbor's, never hers and never the door's, and the count below is only so
|
|
15
15
|
// that a loop in this session stops somewhere a human can see.
|
|
16
16
|
import { Being, isSilence, isWord, wordOf } from 'nervur';
|
|
17
|
+
import { Doorbell } from './doorbell.js';
|
|
17
18
|
const ROOM = 64;
|
|
18
19
|
export class Porter extends Being {
|
|
19
20
|
static cells = { minted: 0 };
|
|
@@ -24,8 +25,11 @@ export class Porter extends Being {
|
|
|
24
25
|
const minted = typeof this.cells.minted === 'number' ? this.cells.minted : 0;
|
|
25
26
|
if (minted >= ROOM)
|
|
26
27
|
return { error: 'this bell holds no more doorbells' };
|
|
28
|
+
// The class says where it lives and the porter reads it off her. A path
|
|
29
|
+
// spelled here would be the doorbell named by whoever boots her, which
|
|
30
|
+
// is a class described by someone who is not it.
|
|
27
31
|
const key = `doorbell:${minted + 1}`;
|
|
28
|
-
const held = await this.boot(
|
|
32
|
+
const held = await this.boot(Doorbell.at, key, key);
|
|
29
33
|
if (held === null)
|
|
30
34
|
return { error: 'this bell could not make a doorbell' };
|
|
31
35
|
this.cells.minted = minted + 1;
|
|
@@ -3,6 +3,7 @@ import { Avatar } from './avatar.ts';
|
|
|
3
3
|
export declare class Presence extends Avatar {
|
|
4
4
|
static carries(occupant: OccupantRecord | undefined, _asker: Asker): boolean;
|
|
5
5
|
static skips(id: string): boolean;
|
|
6
|
+
static needs: import("nervur").Blueprint[];
|
|
6
7
|
readonly lent: Promise<Record<string, string | null>>;
|
|
7
8
|
constructor(stance: Stance);
|
|
8
9
|
}
|