@fungi.computer/oyster 0.4.1 → 0.5.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/dist/agents.d.ts +2 -1
- package/dist/agents.js +63 -8
- package/dist/apps/gate.d.ts +4 -0
- package/dist/apps/gate.js +3 -0
- package/dist/boot-host-script.js +1 -1
- package/dist/build/candidate-cli.mjs +19 -4
- package/dist/channels/binding.d.ts +63 -0
- package/dist/channels/binding.js +85 -0
- package/dist/channels/conversations.d.ts +235 -0
- package/dist/channels/conversations.js +705 -0
- package/dist/channels/ids.d.ts +8 -0
- package/dist/channels/ids.js +15 -0
- package/dist/host.d.ts +1 -1
- package/dist/host.js +21 -4
- package/dist/keys.d.ts +4 -1
- package/dist/keys.js +15 -4
- package/dist/machine-link/authority.d.ts +7 -0
- package/dist/machine-link/delivery.d.ts +12 -0
- package/dist/machine-link/delivery.js +22 -1
- package/dist/machine-link/disposition.d.ts +16 -0
- package/dist/machine-link/disposition.js +65 -0
- package/dist/machine-link/host.d.ts +11 -2
- package/dist/machine-link/host.js +125 -5
- package/dist/machine-link/link.d.ts +4 -0
- package/dist/machine-link/link.js +47 -1
- package/dist/page-script.js +4 -4
- package/dist/standalone/agent-mail.js +4 -1
- package/dist/standalone/agents.d.ts +8 -0
- package/dist/standalone/agents.js +21 -2
- package/dist/standalone/channel-session-door.d.ts +4 -0
- package/dist/standalone/channel-session-door.js +42 -0
- package/dist/standalone/machine-link.d.ts +2 -0
- package/dist/standalone/machine-link.js +34 -1
- package/dist/testing/capabilities.d.ts +2 -0
- package/dist/testing/capabilities.js +3 -1
- package/dist/workers-git.js +1 -1
- package/dist/workers.d.ts +3 -0
- package/docs/api/agents.md +8 -4
- package/docs/api/apps.md +8 -4
- package/docs/api/browser.md +40 -16
- package/docs/api/keys.md +25 -3
- package/docs/api/workers.md +21 -14
- package/docs/site/agent-quickstart.mdx +23 -0
- package/examples/standalone/wrangler.jsonc +3 -4
- package/package.json +28 -16
|
@@ -4,8 +4,16 @@ import * as Schema from "effect/Schema";
|
|
|
4
4
|
import { BirdDogMailSchema } from "@fungi.computer/bird-dog/effect";
|
|
5
5
|
import { agentMailAddressSchema, machineAgentOperationSchema, MachineLinkPostUnavailable, } from "@fungi.computer/seam/machine-link-protocol";
|
|
6
6
|
import { machineLinkFenceFactSchema, machineLinkIdentitySchema, machineLinkName, MachineLinkRefused, } from "./authority.js";
|
|
7
|
+
import { machineLinkDisposition } from "./disposition.js";
|
|
7
8
|
import { MachineLinkHost } from "./host.js";
|
|
8
9
|
const pinKey = "machine-link:identity";
|
|
10
|
+
function isRetainedRelayFence(target, relay, fence) {
|
|
11
|
+
return (relay.teamId === target.teamId &&
|
|
12
|
+
relay.deviceId !== target.deviceId &&
|
|
13
|
+
fence !== null &&
|
|
14
|
+
fence.teamId === relay.teamId &&
|
|
15
|
+
fence.deviceId === relay.deviceId);
|
|
16
|
+
}
|
|
9
17
|
/**
|
|
10
18
|
* One device's link inside its own Durable Object. The host's DO class
|
|
11
19
|
* delegates every entry point here. Identity is pinned on the first live
|
|
@@ -60,6 +68,12 @@ export function createMachineLink(state, options) {
|
|
|
60
68
|
})(envelope.event);
|
|
61
69
|
return { address, mail: body };
|
|
62
70
|
};
|
|
71
|
+
const deliverUndeliverable = async (identity, rawOriginal, rawReply) => {
|
|
72
|
+
const checked = machineLinkDisposition(identity, rawOriginal, rawReply);
|
|
73
|
+
if (checked === undefined)
|
|
74
|
+
return "refused";
|
|
75
|
+
return await authority.deliverUndeliverable(identity, checked.original, checked.reply);
|
|
76
|
+
};
|
|
63
77
|
/**
|
|
64
78
|
* The link's own sender check, whatever the host answered: the facts must
|
|
65
79
|
* name the caller and actor it saw, a hosted caller must be hosted, and a
|
|
@@ -94,6 +108,8 @@ export function createMachineLink(state, options) {
|
|
|
94
108
|
if (envelope.kind !== "agentMail")
|
|
95
109
|
return "refused";
|
|
96
110
|
const { address, mail: body } = mail(envelope);
|
|
111
|
+
if (body.from.kind !== "agent")
|
|
112
|
+
return "refused";
|
|
97
113
|
const caller = {
|
|
98
114
|
kind: "device",
|
|
99
115
|
deviceId: identity.deviceId,
|
|
@@ -118,6 +134,7 @@ export function createMachineLink(state, options) {
|
|
|
118
134
|
replay: openReplayStore,
|
|
119
135
|
directory: () => authority.directory(identity),
|
|
120
136
|
receive: (_device, envelope) => receive(identity, envelope),
|
|
137
|
+
disposition: (original, reply) => deliverUndeliverable(identity, original, reply),
|
|
121
138
|
scheduleWake: (at) => state.storage.setAlarm(at),
|
|
122
139
|
report: options.report,
|
|
123
140
|
}));
|
|
@@ -149,16 +166,45 @@ export function createMachineLink(state, options) {
|
|
|
149
166
|
return "refused";
|
|
150
167
|
const { address, mail: body } = mail(envelope);
|
|
151
168
|
const facts = await checkedTarget(device, caller, agentId, null);
|
|
169
|
+
const senderMatches = body.from.kind === "agent" && body.from.agentId === facts.callerAgentId;
|
|
170
|
+
const systemOfflineDisposition = body.from.kind === "system" &&
|
|
171
|
+
body.reply?.outcome === "undeliverable" &&
|
|
172
|
+
body.reply.reason === "recipient_offline" &&
|
|
173
|
+
body.to.agentId === facts.targetAgentId;
|
|
152
174
|
if (facts.targetHome.kind !== "machine" ||
|
|
153
175
|
facts.targetHome.deviceId !== device.deviceId ||
|
|
154
176
|
envelope.key !== body.key ||
|
|
155
177
|
address.scopeId !== facts.teamId ||
|
|
156
178
|
address.agentId !== facts.targetAgentId ||
|
|
157
179
|
body.to.agentId !== facts.targetAgentId ||
|
|
158
|
-
|
|
180
|
+
(!senderMatches && !systemOfflineDisposition))
|
|
159
181
|
return "refused";
|
|
160
182
|
return await hostFor(device).deliver(device.deviceId, envelope);
|
|
161
183
|
},
|
|
184
|
+
/** A relay's typed terminal reply to an Agent homed on this device. */
|
|
185
|
+
async deliverRelayDisposition(input, relayInput, original, reply) {
|
|
186
|
+
const device = await current(input);
|
|
187
|
+
const relay = machineLinkIdentitySchema.parse(relayInput);
|
|
188
|
+
const retainedRelay = await authority.currentFence(relay);
|
|
189
|
+
if (!isRetainedRelayFence(device, relay, retainedRelay))
|
|
190
|
+
return "refused";
|
|
191
|
+
const checked = machineLinkDisposition(device, original, reply);
|
|
192
|
+
if (checked === undefined)
|
|
193
|
+
return "refused";
|
|
194
|
+
if (!(await authority.verifyRelayDisposition(relay, checked.original, checked.reply)))
|
|
195
|
+
return "refused";
|
|
196
|
+
const home = await authority.agentHome(device, checked.reply.address.agentId);
|
|
197
|
+
if (home?.kind !== "machine" || home.deviceId !== device.deviceId)
|
|
198
|
+
return "refused";
|
|
199
|
+
return await hostFor(device).deliver(device.deviceId, checked.reply, {
|
|
200
|
+
refuseDuplicate: true,
|
|
201
|
+
});
|
|
202
|
+
},
|
|
203
|
+
/** Attest a still-pending disposition in this device's own Post outbox. */
|
|
204
|
+
async hasStagedDisposition(input, original, reply) {
|
|
205
|
+
const device = await current(input);
|
|
206
|
+
return await hostFor(device).hasStagedDisposition(device.deviceId, original, reply);
|
|
207
|
+
},
|
|
162
208
|
/** One finite Agent operation on this device, returning its receipt. */
|
|
163
209
|
async operation(input, caller, agentId, raw) {
|
|
164
210
|
const device = await current(input);
|