@nervur-org/dock 0.3.0 → 0.4.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/GETTING_STARTED.md +22 -12
- package/{beings/GLOSSARY.md → GLOSSARY.md} +3 -3
- package/NOTICE +1 -1
- package/README.md +20 -16
- package/{beings/WORLDS.md → WORLDS.md} +6 -4
- package/api/route.ts +3 -3
- package/beings/avatar.ts +2 -2
- package/beings/carry.ts +2 -2
- package/beings/clock.ts +2 -2
- package/beings/courier.ts +2 -2
- package/beings/desk.ts +2 -2
- package/beings/doorbell.ts +2 -2
- package/beings/envoy.ts +2 -2
- package/beings/join.ts +2 -2
- package/beings/link.ts +5 -5
- package/beings/look.ts +1 -1
- package/beings/porter.ts +2 -2
- package/beings/presence.ts +1 -1
- package/beings/setup.ts +3 -3
- package/beings/side.ts +2 -2
- package/beings/user.ts +2 -2
- package/beings/way.ts +1 -1
- package/cli/client.ts +6 -6
- package/cli/daemon.ts +7 -7
- package/cli/estate/{quo.service → nervur.service} +12 -12
- package/cli/estate/org.nervur.plist +44 -0
- package/cli/estate.ts +6 -6
- package/cli/{quo.ts → nervur.ts} +43 -37
- package/cli/pilot.ts +3 -3
- package/cli/stand.ts +3 -3
- package/dist/api/route.d.ts +2 -2
- package/dist/api/route.js +2 -2
- package/dist/beings/avatar.d.ts +1 -1
- package/dist/beings/avatar.js +1 -1
- package/dist/beings/carry.d.ts +2 -2
- package/dist/beings/carry.js +1 -1
- package/dist/beings/clock.d.ts +2 -2
- package/dist/beings/clock.js +1 -1
- package/dist/beings/courier.d.ts +2 -2
- package/dist/beings/courier.js +1 -1
- package/dist/beings/desk.d.ts +3 -3
- package/dist/beings/desk.js +1 -1
- package/dist/beings/doorbell.d.ts +3 -3
- package/dist/beings/doorbell.js +1 -1
- package/dist/beings/envoy.d.ts +2 -2
- package/dist/beings/envoy.js +1 -1
- package/dist/beings/join.d.ts +2 -2
- package/dist/beings/link.d.ts +2 -2
- package/dist/beings/link.js +3 -3
- package/dist/beings/look.d.ts +1 -1
- package/dist/beings/porter.d.ts +2 -2
- package/dist/beings/porter.js +1 -1
- package/dist/beings/presence.d.ts +1 -1
- package/dist/beings/setup.d.ts +1 -1
- package/dist/beings/side.d.ts +1 -1
- package/dist/beings/side.js +1 -1
- package/dist/beings/user.d.ts +3 -3
- package/dist/beings/user.js +1 -1
- package/dist/beings/way.d.ts +1 -1
- package/dist/cli/client.js +4 -4
- package/dist/cli/daemon.d.ts +1 -1
- package/dist/cli/daemon.js +6 -6
- package/dist/cli/estate/{quo.service → nervur.service} +12 -12
- package/dist/cli/estate/org.nervur.plist +44 -0
- package/dist/cli/estate.js +6 -6
- package/dist/cli/{quo.js → nervur.js} +43 -37
- package/dist/cli/stand.d.ts +2 -2
- package/dist/dock/agents.d.ts +1 -1
- package/dist/dock/agents.js +1 -1
- package/dist/dock/apns.js +1 -1
- package/dist/dock/console.d.ts +1 -1
- package/dist/dock/dialers.d.ts +2 -2
- package/dist/dock/dialers.js +2 -2
- package/dist/dock/faculty.d.ts +2 -2
- package/dist/dock/faculty.js +1 -1
- package/dist/dock/grants.d.ts +1 -1
- package/dist/dock/grants.js +1 -1
- package/dist/dock/http2.js +1 -1
- package/dist/dock/index.d.ts +1 -1
- package/dist/dock/index.js +1 -1
- package/dist/dock/local.d.ts +2 -2
- package/dist/dock/location.d.ts +1 -1
- package/dist/dock/notifications.d.ts +1 -1
- package/dist/dock/notifications.js +1 -1
- package/dist/dock/push.d.ts +1 -1
- package/dist/dock/push.js +3 -3
- package/dist/dock/service.js +1 -1
- package/dist/dock/timer.d.ts +1 -1
- package/dist/harbor/browser.d.ts +2 -2
- package/dist/harbor/browser.js +4 -4
- package/dist/harbor/capacitor.d.ts +1 -1
- package/dist/harbor/capacitor.js +1 -1
- package/dist/harbor/disk.d.ts +4 -4
- package/dist/harbor/disk.js +5 -5
- package/dist/harbor/edge/edge.d.ts +2 -2
- package/dist/harbor/edge/edge.js +5 -5
- package/dist/harbor/edge/exercise.js +8 -8
- package/dist/harbor/edge/given.d.ts +1 -1
- package/dist/harbor/edge/platform.d.ts +1 -1
- package/dist/harbor/edge/storage.d.ts +1 -1
- package/dist/harbor/edge/storage.js +2 -2
- package/dist/harbor/edge/worker.js +2 -2
- package/dist/harbor/files.d.ts +1 -1
- package/dist/harbor/files.js +2 -2
- package/dist/harbor/http.d.ts +2 -2
- package/dist/harbor/http.js +1 -1
- package/dist/harbor/idb.d.ts +1 -1
- package/dist/harbor/idb.js +0 -0
- package/dist/harbor/quo.js +1 -1
- package/dist/harbor/seal.js +1 -1
- package/dist/harbor/sealed.d.ts +1 -1
- package/dist/harbor/sealed.js +4 -4
- package/dist/harbor/tauri.d.ts +1 -1
- package/dist/harbor/tauri.js +1 -1
- package/dist/harbor/ward.d.ts +1 -1
- package/dist/human/app.d.ts +2 -2
- package/dist/human/door.js +4 -4
- package/dist/human/guest.js +1 -1
- package/dist/human/html.d.ts +1 -1
- package/dist/human/html.js +1 -1
- package/dist/human/local.d.ts +1 -1
- package/dist/human/mark.js +2 -2
- package/dist/human/move.d.ts +2 -2
- package/dist/human/move.js +1 -1
- package/dist/human/screen.d.ts +1 -1
- package/dist/human/screen.js +3 -3
- package/dist/human/tab.bundle.txt +32 -32
- package/dist/human/tab.js +7 -7
- package/dist/human/tree.d.ts +1 -1
- package/dist/human/wake.d.ts +2 -2
- package/dist/human/wake.js +1 -1
- package/dist/human/web.d.ts +1 -1
- package/dist/human/web.js +4 -4
- package/dist/human/worker.bundle.txt +27 -27
- package/dist/human/worker.js +4 -4
- package/dist/human/worlds.d.ts +2 -2
- package/dist/human/worlds.js +4 -4
- package/dist/mcp/agent.d.ts +1 -1
- package/dist/mcp/allow.d.ts +1 -1
- package/dist/mcp/allow.js +2 -2
- package/dist/mcp/oauth.js +1 -1
- package/dist/mcp/runner.d.ts +1 -1
- package/dist/mcp/server.d.ts +2 -2
- package/dist/mcp/server.js +2 -2
- package/dock/agents.ts +2 -2
- package/dock/apns.ts +1 -1
- package/dock/console.ts +1 -1
- package/dock/dialers.ts +3 -3
- package/dock/faculty.ts +2 -2
- package/dock/grants.ts +2 -2
- package/dock/http2.ts +1 -1
- package/dock/index.ts +3 -3
- package/dock/local.ts +1 -1
- package/dock/location.ts +1 -1
- package/dock/notifications.ts +2 -2
- package/dock/push.ts +4 -4
- package/dock/service.ts +1 -1
- package/dock/timer.ts +1 -1
- package/harbor/browser.ts +5 -5
- package/harbor/capacitor.ts +2 -2
- package/harbor/disk.ts +8 -8
- package/harbor/edge/edge.ts +7 -7
- package/harbor/edge/exercise.ts +11 -11
- package/harbor/edge/given.ts +1 -1
- package/harbor/edge/platform.d.ts +1 -1
- package/harbor/edge/storage.ts +2 -2
- package/harbor/edge/worker.ts +2 -2
- package/harbor/edge/wrangler.toml +3 -3
- package/harbor/files.ts +2 -2
- package/harbor/http.ts +2 -2
- package/harbor/idb.ts +0 -0
- package/harbor/quo.ts +1 -1
- package/harbor/resolve.ts +1 -1
- package/harbor/seal.ts +1 -1
- package/harbor/sealed.ts +5 -5
- package/harbor/tauri.ts +2 -2
- package/harbor/ward.ts +1 -1
- package/human/app.ts +2 -2
- package/human/apps.ts +1 -1
- package/human/door.ts +4 -4
- package/human/guest.ts +2 -2
- package/human/html.ts +2 -2
- package/human/local.ts +1 -1
- package/human/mark.ts +2 -2
- package/human/move.ts +3 -3
- package/human/screen.ts +5 -5
- package/human/tab.bundle.txt +32 -32
- package/human/tab.ts +10 -10
- package/human/tree.ts +1 -1
- package/human/wake.ts +3 -3
- package/human/web.ts +5 -5
- package/human/worker.bundle.txt +27 -27
- package/human/worker.ts +6 -6
- package/human/worlds.ts +5 -5
- package/mcp/agent.ts +1 -1
- package/mcp/allow.ts +5 -5
- package/mcp/oauth.ts +1 -1
- package/mcp/runner.ts +1 -1
- package/mcp/server.ts +3 -3
- package/package.json +15 -7
- package/{api/quo-api.md → quo-api.md} +1 -1
- package/{beings/quo-dock.md → quo-dock.md} +74 -71
- package/{harbor/quo-harbor.md → quo-harbor.md} +54 -30
- package/{human/quo-human.md → quo-human.md} +7 -7
- package/{mcp/quo-mcp.md → quo-mcp.md} +10 -10
- package/cli/estate/systems.quo.plist +0 -44
- package/cli/quo-dock.md +0 -1942
- package/dist/cli/estate/systems.quo.plist +0 -44
- package/dock/quo-app-bells.md +0 -280
- package/dock/quo-dock.md +0 -1942
- /package/dist/cli/{quo.d.ts → nervur.d.ts} +0 -0
- /package/{beings/quo-app-bells.md → quo-app-bells.md} +0 -0
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
-
<!--
|
|
3
|
-
The daemon on a Mac, as the user, forever: a launchd agent. It holds the
|
|
4
|
-
harbor at ~/.quo and the socket to every quo. route ~/.quo/dial.json
|
|
5
|
-
names, so a Mac behind NAT is reached through the droplet it dialed. The
|
|
6
|
-
daemon runs the dock's emitted `dist/cli/quo.js` from where the estate
|
|
7
|
-
installed it, never the source. Install, with node on the path:
|
|
8
|
-
|
|
9
|
-
sed "s#HOME#$HOME#g; s#NODE#$(which node)#g" mac/systems.quo.plist > ~/Library/LaunchAgents/systems.quo.plist
|
|
10
|
-
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/systems.quo.plist
|
|
11
|
-
|
|
12
|
-
Remove with `launchctl bootout gui/$(id -u)/systems.quo`; restart after a
|
|
13
|
-
wire change with `launchctl kickstart -k gui/$(id -u)/systems.quo`. The
|
|
14
|
-
log is ~/.quo/serve.log. No HTTP door: a Mac is a dialer, not a listener.
|
|
15
|
-
-->
|
|
16
|
-
<plist version="1.0">
|
|
17
|
-
<dict>
|
|
18
|
-
<key>Label</key>
|
|
19
|
-
<string>systems.quo</string>
|
|
20
|
-
<key>ProgramArguments</key>
|
|
21
|
-
<array>
|
|
22
|
-
<string>NODE</string>
|
|
23
|
-
<string>HOME/ESTATE/node_modules/@nervur-org/dock/dist/cli/quo.js</string>
|
|
24
|
-
<string>serve</string>
|
|
25
|
-
</array>
|
|
26
|
-
<key>EnvironmentVariables</key>
|
|
27
|
-
<dict>
|
|
28
|
-
<key>QUO_DIR</key>
|
|
29
|
-
<string>HOME/.quo</string>
|
|
30
|
-
</dict>
|
|
31
|
-
<key>WorkingDirectory</key>
|
|
32
|
-
<string>HOME/ESTATE</string>
|
|
33
|
-
<key>RunAtLoad</key>
|
|
34
|
-
<true/>
|
|
35
|
-
<key>KeepAlive</key>
|
|
36
|
-
<true/>
|
|
37
|
-
<key>ThrottleInterval</key>
|
|
38
|
-
<integer>2</integer>
|
|
39
|
-
<key>StandardOutPath</key>
|
|
40
|
-
<string>HOME/.quo/serve.log</string>
|
|
41
|
-
<key>StandardErrorPath</key>
|
|
42
|
-
<string>HOME/.quo/serve.log</string>
|
|
43
|
-
</dict>
|
|
44
|
-
</plist>
|
package/dock/quo-app-bells.md
DELETED
|
@@ -1,280 +0,0 @@
|
|
|
1
|
-
# The bells of a Quo app
|
|
2
|
-
|
|
3
|
-
A ward on a dialer is reachable only while it holds a line. A closed tab, a
|
|
4
|
-
phone asleep, an app in the background: the world has something to say and
|
|
5
|
-
nobody is listening. The bell is how such a device is reached, the one way
|
|
6
|
-
its platform allows, by waking it.
|
|
7
|
-
|
|
8
|
-
Everything here is four pieces, and none of them is any publisher's. An
|
|
9
|
-
adopter who ships their own Quo app under their own name runs the same four
|
|
10
|
-
with their own keys, changes nothing in the library and nothing in the dock,
|
|
11
|
-
and is not asking anyone's permission.
|
|
12
|
-
|
|
13
|
-
## Why a service exists at all
|
|
14
|
-
|
|
15
|
-
Apple and Google accept a push only when it is signed with the key of the
|
|
16
|
-
team that published the app. A world's box holds no such key and never
|
|
17
|
-
will, because the key belongs to whoever publishes the app and to nobody
|
|
18
|
-
else. So a world hands the ring on to a service that publisher runs.
|
|
19
|
-
|
|
20
|
-
This is the one place in Quo where a world does not reach a person
|
|
21
|
-
directly, and it is not a design choice. It is the platform's rule, and the
|
|
22
|
-
whole of this paper is about making that hop carry as little as it possibly
|
|
23
|
-
can.
|
|
24
|
-
|
|
25
|
-
Web Push needs no service. A world mints its own keypair and speaks to the
|
|
26
|
-
browser's push service itself, so tabs and desks are free of this entirely.
|
|
27
|
-
|
|
28
|
-
## The porter
|
|
29
|
-
|
|
30
|
-
A bell is a ward, and its public being is the porter. A phone nobody knows
|
|
31
|
-
arrives at her as `{}`, which is the one place in Quo a stranger is
|
|
32
|
-
answered by design.
|
|
33
|
-
|
|
34
|
-
She does one thing. A device says hello, she brings a doorbell into being
|
|
35
|
-
for it, and hands back the way in. The device knocks, and from then on it is
|
|
36
|
-
a named occupant with a heir and a count, which is where anything that must
|
|
37
|
-
happen once belongs. Her own answer is safe to repeat, as a public being's
|
|
38
|
-
must be: saying hello twice is two doorbells and no harm.
|
|
39
|
-
|
|
40
|
-
A stranger who keeps knocking is the harbor's, never hers and never the
|
|
41
|
-
door's. A bell needs no attestation, no account and no door of its own
|
|
42
|
-
invention, and it should have none.
|
|
43
|
-
|
|
44
|
-
## The doorbell
|
|
45
|
-
|
|
46
|
-
One being per device. Two things live in it.
|
|
47
|
-
|
|
48
|
-
**The platform token**, in her cells, written by the device and read by
|
|
49
|
-
nobody. It leaves for nowhere. No world ever sees it, so no world can copy
|
|
50
|
-
it, hand it on, or keep ringing after it is told to stop. When the platform
|
|
51
|
-
hands the phone a new token, the phone writes it here once and not one world
|
|
52
|
-
is told anything.
|
|
53
|
-
|
|
54
|
-
**One occupant per allowed world.** The device asks the doorbell for a way
|
|
55
|
-
in, hands it to a world it has joined, and that world knocks and holds an
|
|
56
|
-
ordinary standing. That row is the whole of the permission, and it is held
|
|
57
|
-
at the bell, by neither the world that rings nor the publisher who holds the
|
|
58
|
-
key.
|
|
59
|
-
|
|
60
|
-
So the pair is recorded independently: this device, that world. A device
|
|
61
|
-
with presence in many worlds has many rows here, and every one of them
|
|
62
|
-
stands or falls on its own.
|
|
63
|
-
|
|
64
|
-
## Allowing and disallowing
|
|
65
|
-
|
|
66
|
-
**Allowing is an invitation the device mints.** A world can only ring a
|
|
67
|
-
phone that chose it. There is no list of approved worlds anywhere, and there
|
|
68
|
-
must not be: gating it would make the publisher the gatekeeper of every
|
|
69
|
-
world's relation with its own member, which is the thing Quo exists to
|
|
70
|
-
abolish, and it buys nothing, because the consent is already there in the
|
|
71
|
-
act of handing over the invitation.
|
|
72
|
-
|
|
73
|
-
**Disallowing is `remove`.** One occupant goes. The heir is forgotten and
|
|
74
|
-
its last keys are kept apart, bounded, so that world hears `removed` once at
|
|
75
|
-
the door and nobody else hears a thing. Her other worlds are untouched. It
|
|
76
|
-
takes effect at the bell, so it does not depend on the removed world being
|
|
77
|
-
honest about it, and there is nothing it could have kept that would still
|
|
78
|
-
work.
|
|
79
|
-
|
|
80
|
-
## What a ring carries
|
|
81
|
-
|
|
82
|
-
A world rings its standing. It names no device, no token and no world,
|
|
83
|
-
because the doorbell reads both ends from the standing the ask arrived on.
|
|
84
|
-
There is nothing in a ring to forge.
|
|
85
|
-
|
|
86
|
-
It carries one thing: a payload sealed to the device's own key. Not to the
|
|
87
|
-
bell's, not to the world's, not to anyone else's. The bell passes ciphertext
|
|
88
|
-
it could not read if it tried, the platform carries ciphertext, and on the
|
|
89
|
-
device a notification service extension unseals it before the banner is
|
|
90
|
-
drawn. What the person sees is an ordinary, immediate notification.
|
|
91
|
-
|
|
92
|
-
So the claim is not that the doorbell carries nothing. It is that the
|
|
93
|
-
doorbell carries nothing anyone but her device can read, which is the
|
|
94
|
-
stronger promise, because the weaker one bought its purity with the banner
|
|
95
|
-
itself: a notification composed after the app wakes is one the platform may
|
|
96
|
-
delay at its own discretion and one a person who force quit the app never
|
|
97
|
-
sees at all.
|
|
98
|
-
|
|
99
|
-
The payload is bounded by what the platform will carry, four kilobytes on
|
|
100
|
-
APNs, and the doorbell refuses a seal that will not fit rather than letting
|
|
101
|
-
a platform nobody is reading refuse it two hops later.
|
|
102
|
-
|
|
103
|
-
Web Push carries the same line and seals it once rather than twice. The
|
|
104
|
-
standard encrypts a body to keys only that browser holds, so the only party
|
|
105
|
-
a banner key would hide it from is the push service, which that encryption
|
|
106
|
-
already excludes. A second seal would buy nothing and would make every tab
|
|
107
|
-
keep a banner key for it. So a world encrypts the line itself, the browser
|
|
108
|
-
opens it, and the worker shows what it was handed.
|
|
109
|
-
|
|
110
|
-
## Where a bell runs
|
|
111
|
-
|
|
112
|
-
Anywhere a harbor runs, and it is the same bell. A bell is a ward: the
|
|
113
|
-
porter, a doorbell per device, and the push faculty of the ward it stands
|
|
114
|
-
on. Nothing in it knows a platform.
|
|
115
|
-
|
|
116
|
-
What differs is one thing, and it is the thing a faculty is for. The
|
|
117
|
-
faculty's rings are built by the terrain out of what that terrain has: a
|
|
118
|
-
worker's `fetch` speaks HTTP/2 and an edge bell rings APNs with it, a
|
|
119
|
-
droplet speaks it with `node:http2` and rings the same service, and a
|
|
120
|
-
terrain with neither holds no `apns` ring and says so. A publisher who
|
|
121
|
-
starts on a worker and moves to a box moves the ward, keeps its pk, and
|
|
122
|
-
neither a device's standing nor a world's is disturbed.
|
|
123
|
-
|
|
124
|
-
So the edge is a convenience and never a requirement. It is a good first
|
|
125
|
-
home because a bell keeps almost nothing and must answer whenever any world
|
|
126
|
-
rings, and that is all it is.
|
|
127
|
-
|
|
128
|
-
## Nothing is configured
|
|
129
|
-
|
|
130
|
-
A bell has no configuration file and wants none. What it holds, it holds the
|
|
131
|
-
way every being holds anything.
|
|
132
|
-
|
|
133
|
-
- **Who may ring** is an occupant, invited by the device.
|
|
134
|
-
- **What is rung** is a token in a doorbell's cells, written by the device.
|
|
135
|
-
- **Which service a world hands a ring to** is a cell on the push faculty,
|
|
136
|
-
set by the root, because whose service it is belongs to an estate and not
|
|
137
|
-
to a world.
|
|
138
|
-
- **The platform keys** are the terrain's secrets and reach the faculty as
|
|
139
|
-
its rings are built, never a file in a tree and never a cell.
|
|
140
|
-
|
|
141
|
-
Rotation is the same answer twice. A heir rotates as it speaks, which is
|
|
142
|
-
Quo's and needs nobody. A platform token rotates by the device writing it
|
|
143
|
-
once, and because no world was ever given one, no world is told.
|
|
144
|
-
|
|
145
|
-
## The banner key
|
|
146
|
-
|
|
147
|
-
A world seals to a key that opens banners and nothing else.
|
|
148
|
-
|
|
149
|
-
It is the device's, one pair, and it lives in the cells of the box's
|
|
150
|
-
notifications faculty, which is the being that shows a human a line. That is
|
|
151
|
-
the source of truth and the only place the pair is kept. The public half
|
|
152
|
-
goes to a world when the device admits it, beside the invitation to the
|
|
153
|
-
doorbell. The secret half never leaves the device.
|
|
154
|
-
|
|
155
|
-
Where a platform's own notification process can read it is the faculty's
|
|
156
|
-
business, and this is the whole reason the key sits there rather than in a
|
|
157
|
-
being of the library's. On a phone the extension that draws the banner is a
|
|
158
|
-
second process, so the faculty puts the secret in the keychain group it
|
|
159
|
-
shares with it. On a desk and in a tab the terrain has its own answer. A
|
|
160
|
-
faculty is the terrain's hand, and a key that must be reachable by the
|
|
161
|
-
platform belongs in the hand and not in the library.
|
|
162
|
-
|
|
163
|
-
A tab keeps none. Web Push is encrypted to the subscription's own keys and
|
|
164
|
-
a browser draws its own banners in its own worker, so there is neither a
|
|
165
|
-
second process to reach nor a second seal to open.
|
|
166
|
-
|
|
167
|
-
Minting the key is where the person is asked. A device that has just minted
|
|
168
|
-
one is a device about to be rung, and the ring that carries a banner is an
|
|
169
|
-
alert the platform draws for nobody who has not allowed it. Registering for
|
|
170
|
-
the doorbell asked for nothing, deliberately, because a doorbell displays
|
|
171
|
-
nothing; so the phone asks in the same act as it plants the key, and a
|
|
172
|
-
refusal costs the line and not the wake. The key stays where it is, the
|
|
173
|
-
world is admitted, and what arrives is a push the person reads when she
|
|
174
|
-
opens the app.
|
|
175
|
-
|
|
176
|
-
It is not the ward's own key, and that is deliberate. The ward's seed opens
|
|
177
|
-
everything the person sees and is kept so that it never leaves the device at
|
|
178
|
-
all. A banner key opens banners. If the process that draws notifications
|
|
179
|
-
were ever turned against her, the second loses her a line of text and the
|
|
180
|
-
first would lose her the world.
|
|
181
|
-
|
|
182
|
-
## What a bell knows, and what it cannot
|
|
183
|
-
|
|
184
|
-
It knows which device, which world, and when. It cannot know what was said.
|
|
185
|
-
|
|
186
|
-
That is the honest accounting, and the design holds it to the minimum: keep
|
|
187
|
-
counters and no log of rings, name a doorbell by nothing that identifies a
|
|
188
|
-
person, and hold occupants as keys with no world's name beside them. A bell
|
|
189
|
-
that kept more would be a registry of worlds, and the app exists not to have
|
|
190
|
-
one.
|
|
191
|
-
|
|
192
|
-
The publisher cannot add a world to a device's doorbell. Only the device
|
|
193
|
-
can, because only the device holds the standing that mints a way in. The
|
|
194
|
-
list is held at the bell and it is not the bell's to write.
|
|
195
|
-
|
|
196
|
-
## The three kinds
|
|
197
|
-
|
|
198
|
-
**Web.** A world mints its own keypair and rings the browser's push service
|
|
199
|
-
itself. The line rides in the ring, encrypted end to end by the standard to
|
|
200
|
-
the two keys of that subscription, no bell is involved, and no banner key is
|
|
201
|
-
wanted.
|
|
202
|
-
|
|
203
|
-
**iOS.** APNs, signed under the publisher's key, spoken over HTTP/2. The
|
|
204
|
-
service extension is what makes a sealed payload into a banner, and it needs
|
|
205
|
-
the device's key reachable from a second process.
|
|
206
|
-
|
|
207
|
-
**Android.** The same shape under FCM, with a data message the app composes
|
|
208
|
-
from.
|
|
209
|
-
|
|
210
|
-
A bell that holds no key for a kind says so to whoever rings that kind,
|
|
211
|
-
which is what a publisher who rings no Android phones says to an Android
|
|
212
|
-
phone. It does not pretend it rang.
|
|
213
|
-
|
|
214
|
-
## What this refuses
|
|
215
|
-
|
|
216
|
-
- **An account at the bell.** The standing is the identity. An account would
|
|
217
|
-
be the registry of worlds, and there is no third thing it would buy.
|
|
218
|
-
- **Approving worlds.** The device approves. Nobody else is asked.
|
|
219
|
-
- **A token that travels.** The moment a world holds one, disallowing is a
|
|
220
|
-
request rather than a fact.
|
|
221
|
-
- **A payload the bell can read.** Including one it merely promises not to.
|
|
222
|
-
- **A configuration file.** A bell is occupants, standings and cells. A
|
|
223
|
-
second place to say who may ring would be a second answer to a question
|
|
224
|
-
that already has one.
|
|
225
|
-
- **A terrain in the design.** Edge or droplet is where the ward sleeps, and
|
|
226
|
-
a bell that worked one way on one and another way on the other would be
|
|
227
|
-
two bells.
|
|
228
|
-
- **Anything publisher-specific in the packages.** Team ids, bundle ids, a
|
|
229
|
-
bell's address and a push key are an estate's, carried in by its
|
|
230
|
-
environment. What is published is the porter, the doorbell, the faculty
|
|
231
|
-
and the service, and they name nobody.
|
|
232
|
-
|
|
233
|
-
## Where the tree stands
|
|
234
|
-
|
|
235
|
-
The one place under this paper where a gap between it and the code is named.
|
|
236
|
-
|
|
237
|
-
Each of the three grounds has drawn a line on a screen, and each in the
|
|
238
|
-
shape this paper gives it. On an iPhone the app minted its banner key,
|
|
239
|
-
planted the secret half where the extension reads it, took a device token
|
|
240
|
-
from Apple, and a ring under the team's own key carried a hundred and
|
|
241
|
-
thirty bytes of ciphertext that the extension opened. On Android the ring
|
|
242
|
-
carried an empty data map and the device composed the line itself. In a
|
|
243
|
-
real Chrome the world found the tab unreachable, rang its subscription, and
|
|
244
|
-
the worker drew what it was handed.
|
|
245
|
-
|
|
246
|
-
- **A simulator draws no sealed banner**, because it runs no notification
|
|
247
|
-
service extension at all. It proves everything on either side of that
|
|
248
|
-
move: the pair minted and kept across a reinstall, the secret half
|
|
249
|
-
planted, and the seal opened by the extension's own code against a
|
|
250
|
-
payload a world sealed to that device. The move itself is an iPhone's.
|
|
251
|
-
- **A browser wants a real one.** The Chromium a bench drives answers
|
|
252
|
-
`showNotification` neither way, so the line that draws it is the one line
|
|
253
|
-
no test here runs. A browser also asks the human with a button and never
|
|
254
|
-
on load, so the permission is a click and no suite can spring it.
|
|
255
|
-
- **Android is pointed at a Firebase project by a file a build carries**
|
|
256
|
-
and the tree ignores, since the file holds a key. The project is the
|
|
257
|
-
publisher's own and holds the one app it ships. Its id is minted once and
|
|
258
|
-
never moves, so a project opened for something else keeps that name for
|
|
259
|
-
as long as it lives, which is a thing to know before opening one.
|
|
260
|
-
- **The ring on real hardware holds past the first.** A phone with the app
|
|
261
|
-
backgrounded draws the banner, and so does one locked with the screen
|
|
262
|
-
off. Five rings two seconds apart all arrived, in order, none coalesced
|
|
263
|
-
and none dropped, so the platform throttles nothing at that rate. And a
|
|
264
|
-
ring lands after a full power cycle on an app that has not run since the
|
|
265
|
-
device booted, which is custody at its strongest: the doorbell standing
|
|
266
|
-
and the banner key are both kept, and nothing has to be launched to
|
|
267
|
-
receive. A background push reaches no app the human force quit, by
|
|
268
|
-
Apple's rule, so a phone under test is backgrounded and not closed.
|
|
269
|
-
- **An Android device reaches its bell over `wss` and never `ws`.** The
|
|
270
|
-
shell is served from `https://localhost` there, and that ground's WebView
|
|
271
|
-
refuses a cleartext socket from an HTTPS page as mixed content, so a bell
|
|
272
|
-
on a bare address on the same network cannot be dialled at all and the
|
|
273
|
-
device comes away with no doorbell. A phone's WebView on the other ground
|
|
274
|
-
allows it. So a bell under test wants a real name and a certificate,
|
|
275
|
-
where the other ground is content with an address on the wire.
|
|
276
|
-
- **A ring costs about 290ms on the box side**, measured from the ask to
|
|
277
|
-
the answer that comes back only once the bell has handed it to Apple and
|
|
278
|
-
Apple has taken it. It is steady under a burst: five rings measured 291,
|
|
279
|
-
294, 291, 295 and 295. What the platform then does with it before a
|
|
280
|
-
screen lights is the platform's and is not ours to measure.
|