@agentorg/cli 0.0.3 → 0.0.4
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 +14 -10
- package/dist/bundled/index.json +4 -4
- package/dist/bundled/{sha256-87e121cbe58279f3a633e61c9773b61fc17fd53eac3d7c6f037925cbfd5d5384.agentorg → sha256-01d69bc3888c2a53963f4413d47de909d129ad27c78e9af6d830bb50c3478419.agentorg} +0 -0
- package/dist/bundled/{sha256-51ecf151e590f5e57f28229d4cb36e4932a2f1670e50ddf1a3ccf335a1ee146d.agentorg → sha256-84165e3be5c904fc971d983dab31102e07cca725d8629a6fd7d118fa3a0a88b8.agentorg} +0 -0
- package/dist/bundled/sha256-ade9132b3f34b4c39db92adeadc7e540dc745e4a81b5b54f5d45bf9ec92bca75.agentorg +0 -0
- package/dist/bundled/{sha256-b76ec31282e5b863ee9569dfd9d50b283a21101cbe1b3fac23d1cbcf16b9a408.agentorg → sha256-f4330f5987f37d8cf3aeb44d2f831b573641a87186daa2f811f0c35ba04804f0.agentorg} +0 -0
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/build.d.ts +2 -2
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/build.js +14 -4
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/hub-actor.js +8 -0
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/index.d.ts +1 -1
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/index.js +1 -1
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/router.js +40 -16
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/state.d.ts +63 -0
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/state.js +177 -36
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/storage.d.ts +2 -1
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/storage.js +3 -2
- package/{node_modules → dist/node_modules}/@agentorg/hub/package.json +3 -0
- package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/hub.d.ts +43 -3
- package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/hub.js +40 -3
- package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/index.d.ts +1 -0
- package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/index.js +1 -0
- package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/installer.d.ts +37 -0
- package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/installer.js +34 -3
- package/dist/node_modules/@agentorg/interfaces/dist/src/rules.d.ts +35 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/rules.js +37 -0
- package/dist/node_modules/@agentorg/kit/dist/src/chat.d.ts +37 -0
- package/dist/node_modules/@agentorg/kit/dist/src/chat.js +131 -0
- package/dist/node_modules/@agentorg/kit/dist/src/components.d.ts +94 -0
- package/dist/node_modules/@agentorg/kit/dist/src/components.js +66 -0
- package/dist/node_modules/@agentorg/kit/dist/src/icons.d.ts +17 -0
- package/dist/node_modules/@agentorg/kit/dist/src/icons.js +30 -0
- package/dist/node_modules/@agentorg/kit/dist/src/index.d.ts +6 -0
- package/dist/node_modules/@agentorg/kit/dist/src/index.js +10 -0
- package/dist/node_modules/@agentorg/kit/dist/src/markdown.d.ts +9 -0
- package/dist/node_modules/@agentorg/kit/dist/src/markdown.js +14 -0
- package/dist/node_modules/@agentorg/kit/dist/src/resizable.d.ts +5 -0
- package/dist/node_modules/@agentorg/kit/dist/src/resizable.js +8 -0
- package/dist/node_modules/@agentorg/kit/dist/src/styles.d.ts +11 -0
- package/dist/node_modules/@agentorg/kit/dist/src/styles.js +166 -0
- package/dist/node_modules/@agentorg/kit/package.json +44 -0
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/frame/runtime.js +172 -17
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/host/runner.js +168 -11
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/client.d.ts +18 -0
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/client.js +24 -3
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-base.d.ts +8 -0
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-base.js +64 -0
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame-entry.js +4 -4
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame-host.d.ts +1 -10
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame-host.js +0 -23
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame-protocol.d.ts +0 -8
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame.d.ts +0 -2
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame.js +0 -8
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/host.js +5 -0
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/index.d.ts +1 -1
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/module-host.d.ts +6 -1
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/module-host.js +24 -1
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/module.d.ts +30 -1
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/package.js +111 -6
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/runtime.d.ts +22 -1
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/runtime.js +114 -0
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/testing.d.ts +14 -2
- package/dist/node_modules/@agentorg/sdk/dist/src/testing.js +89 -0
- package/{node_modules → dist/node_modules}/@agentorg/shell/dist/app.css +27 -144
- package/dist/node_modules/@agentorg/shell/dist/app.js +219 -0
- package/{node_modules → dist/node_modules}/@agentorg/shell/package.json +1 -0
- package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/index.d.ts +1 -1
- package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/ops.d.ts +14 -1
- package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/ops.js +22 -2
- package/dist/src/cli.js +23 -0
- package/dist/src/gateway.js +42 -1
- package/dist/src/rules.d.ts +71 -0
- package/dist/src/rules.js +157 -0
- package/package.json +13 -16
- package/dist/bundled/sha256-e4c0e857cea3a721998effe2ca859c4011978b9bc36e63c058bfc17c27a1772e.agentorg +0 -0
- package/node_modules/@agentorg/sdk/dist/src/testing.js +0 -51
- package/node_modules/@agentorg/shell/dist/app.js +0 -9
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/hub-actor.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/logs.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/logs.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/net.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/net.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/processes.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/processes.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/router.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/server.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/server.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/validate-worker.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/validate-worker.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/validate.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/validate.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/account-login.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/account-login.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/chat.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/chat.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/http-egress.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/http-egress.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/kv.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/kv.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/layout.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/layout.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/llm-session.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/llm-session.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/storage-admin.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/storage-admin.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/ui-shell.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/ui-shell.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/ui-view.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/ui-view.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/package.json +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/build.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/build.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/canonical.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/canonical.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/cli.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/cli.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/client-http.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/client-http.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/describe.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/describe.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/errors.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/errors.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame-entry.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame-protocol.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/host-main.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/host-main.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/host.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/index.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/interface.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/interface.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/manifest-api.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/manifest-api.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/manifest.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/manifest.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/module.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/package.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/person-commands.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/person-commands.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/tar.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/tar.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/package.json +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/shell/dist/agent-bindings.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/shell/dist/index.html +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/shell/src/agent-bindings.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/bytes.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/bytes.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/frames.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/frames.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/index.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/transports.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/transports.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/yamux.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/yamux.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/package.json +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// src/errors.ts
|
|
2
2
|
var BRAND = /* @__PURE__ */ Symbol.for("@agentorg/sdk/error");
|
|
3
3
|
var isBranded = (value, name) => typeof value === "object" && value !== null && value[BRAND] === name;
|
|
4
|
-
var instanceOf = (asked,
|
|
4
|
+
var instanceOf = (asked, base2, name, value) => (
|
|
5
5
|
// The name is given, not read from the class: a bundler may rename a class.
|
|
6
|
-
asked ===
|
|
6
|
+
asked === base2 ? isBranded(value, name) : Function.prototype[Symbol.hasInstance].call(asked, value)
|
|
7
7
|
);
|
|
8
8
|
var NotConnected = class _NotConnected extends Error {
|
|
9
9
|
static [Symbol.hasInstance](value) {
|
|
@@ -97,7 +97,7 @@ function createRuntime(definition, options) {
|
|
|
97
97
|
if (!state.binding) throw new NotConnected(name);
|
|
98
98
|
return state.binding.provider;
|
|
99
99
|
};
|
|
100
|
-
const
|
|
100
|
+
const base2 = {
|
|
101
101
|
get bound() {
|
|
102
102
|
return state.binding !== void 0;
|
|
103
103
|
},
|
|
@@ -112,7 +112,7 @@ function createRuntime(definition, options) {
|
|
|
112
112
|
};
|
|
113
113
|
switch (iface.kind) {
|
|
114
114
|
case "rpc":
|
|
115
|
-
return Object.assign(
|
|
115
|
+
return Object.assign(base2, {
|
|
116
116
|
call: Object.fromEntries(
|
|
117
117
|
Object.entries(iface.methods).map(([method, spec]) => [
|
|
118
118
|
method,
|
|
@@ -140,7 +140,7 @@ function createRuntime(definition, options) {
|
|
|
140
140
|
}
|
|
141
141
|
});
|
|
142
142
|
case "stream":
|
|
143
|
-
return Object.assign(
|
|
143
|
+
return Object.assign(base2, {
|
|
144
144
|
async open(params) {
|
|
145
145
|
const target2 = provider();
|
|
146
146
|
const parsed = check(iface.open, params, `${name} open`);
|
|
@@ -150,7 +150,7 @@ function createRuntime(definition, options) {
|
|
|
150
150
|
}
|
|
151
151
|
});
|
|
152
152
|
case "http":
|
|
153
|
-
return Object.assign(
|
|
153
|
+
return Object.assign(base2, {
|
|
154
154
|
async fetch(request) {
|
|
155
155
|
const target2 = provider();
|
|
156
156
|
if (!target2.fetch)
|
|
@@ -214,6 +214,102 @@ function createRuntime(definition, options) {
|
|
|
214
214
|
throw new Refused("unimplemented", `${name} hasn't been implemented yet.`);
|
|
215
215
|
return state.impl;
|
|
216
216
|
};
|
|
217
|
+
const exposed = /* @__PURE__ */ new Map();
|
|
218
|
+
const exposedWatchers = /* @__PURE__ */ new Set();
|
|
219
|
+
const exposedChanged = () => {
|
|
220
|
+
const failed = (error) => options.log.error("An onExposed handler threw.", { error: String(error) });
|
|
221
|
+
for (const fn of [...exposedWatchers])
|
|
222
|
+
try {
|
|
223
|
+
const done = fn();
|
|
224
|
+
if (done instanceof Promise) done.catch(failed);
|
|
225
|
+
} catch (error) {
|
|
226
|
+
failed(error);
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
const listenExposed = (slot, state, event) => {
|
|
230
|
+
const entry = state.events.get(event);
|
|
231
|
+
if (state.gone || !entry || entry.stop || !entry.fns.size) return;
|
|
232
|
+
let ended = false;
|
|
233
|
+
let stop;
|
|
234
|
+
stop = state.source.subscribe(
|
|
235
|
+
event,
|
|
236
|
+
(payload) => {
|
|
237
|
+
for (const fn of [...entry.fns])
|
|
238
|
+
try {
|
|
239
|
+
fn(payload);
|
|
240
|
+
} catch (error) {
|
|
241
|
+
options.log.error("An event handler threw.", { slot, event, error: String(error) });
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
// Ended by the provider going: the interest stays for when it is usable again.
|
|
245
|
+
() => {
|
|
246
|
+
ended = true;
|
|
247
|
+
if (entry.stop === stop) entry.stop = void 0;
|
|
248
|
+
}
|
|
249
|
+
);
|
|
250
|
+
if (!ended) entry.stop = stop;
|
|
251
|
+
};
|
|
252
|
+
const exposedHandle = (slot, state) => {
|
|
253
|
+
const { described, provider } = state.source;
|
|
254
|
+
return Object.freeze({
|
|
255
|
+
slot,
|
|
256
|
+
described,
|
|
257
|
+
provider: Object.freeze({ actor: provider.actor, export: provider.export }),
|
|
258
|
+
call: Object.freeze(
|
|
259
|
+
Object.fromEntries(
|
|
260
|
+
(described.kind === "rpc" ? Object.keys(described.methods) : []).map((method) => [
|
|
261
|
+
method,
|
|
262
|
+
async (input) => {
|
|
263
|
+
if (state.gone) throw new NotConnected(slot);
|
|
264
|
+
return state.source.call(method, input);
|
|
265
|
+
}
|
|
266
|
+
])
|
|
267
|
+
)
|
|
268
|
+
),
|
|
269
|
+
on(event, fn) {
|
|
270
|
+
if (described.kind !== "rpc" || !own(described.events, event))
|
|
271
|
+
throw new TypeError(`${slot} has no event ${event}.`);
|
|
272
|
+
const entry = state.events.get(event) ?? { fns: /* @__PURE__ */ new Set() };
|
|
273
|
+
state.events.set(event, entry);
|
|
274
|
+
entry.fns.add(fn);
|
|
275
|
+
listenExposed(slot, state, event);
|
|
276
|
+
return () => {
|
|
277
|
+
entry.fns.delete(fn);
|
|
278
|
+
if (entry.fns.size) return;
|
|
279
|
+
entry.stop?.();
|
|
280
|
+
entry.stop = void 0;
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
};
|
|
285
|
+
const unexpose = (slot) => {
|
|
286
|
+
const state = exposed.get(slot);
|
|
287
|
+
if (!state) return;
|
|
288
|
+
exposed.delete(slot);
|
|
289
|
+
state.gone = true;
|
|
290
|
+
for (const entry of state.events.values()) {
|
|
291
|
+
entry.stop?.();
|
|
292
|
+
entry.stop = void 0;
|
|
293
|
+
}
|
|
294
|
+
exposedChanged();
|
|
295
|
+
};
|
|
296
|
+
const expose = (slot, source) => {
|
|
297
|
+
const here = exposed.get(slot);
|
|
298
|
+
if (here && here.source.described.hash === source.described.hash && here.source.provider.actor === source.provider.actor && here.source.provider.export === source.provider.export) {
|
|
299
|
+
here.source = source;
|
|
300
|
+
for (const [event, entry] of here.events) {
|
|
301
|
+
entry.stop?.();
|
|
302
|
+
entry.stop = void 0;
|
|
303
|
+
listenExposed(slot, here, event);
|
|
304
|
+
}
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
if (here) unexpose(slot);
|
|
308
|
+
const state = { source, gone: false, events: /* @__PURE__ */ new Map() };
|
|
309
|
+
state.handle = exposedHandle(slot, state);
|
|
310
|
+
exposed.set(slot, state);
|
|
311
|
+
exposedChanged();
|
|
312
|
+
};
|
|
217
313
|
const ctx = {
|
|
218
314
|
slots: Object.fromEntries(
|
|
219
315
|
Object.entries(definition.slots).map(([name, iface]) => [name, slotHandle(name, iface)])
|
|
@@ -239,7 +335,12 @@ function createRuntime(definition, options) {
|
|
|
239
335
|
}
|
|
240
336
|
),
|
|
241
337
|
self: options.self,
|
|
242
|
-
log: options.log
|
|
338
|
+
log: options.log,
|
|
339
|
+
exposed: () => Object.freeze([...exposed.values()].map((state) => state.handle)),
|
|
340
|
+
onExposed(fn) {
|
|
341
|
+
exposedWatchers.add(fn);
|
|
342
|
+
return () => void exposedWatchers.delete(fn);
|
|
343
|
+
}
|
|
243
344
|
};
|
|
244
345
|
const serving = (exportName) => {
|
|
245
346
|
const state = target(exportName, "http");
|
|
@@ -306,6 +407,8 @@ function createRuntime(definition, options) {
|
|
|
306
407
|
if (!state) throw new TypeError(`No slot ${slot}.`);
|
|
307
408
|
if (state.binding) notify(slot, state.binds);
|
|
308
409
|
},
|
|
410
|
+
expose,
|
|
411
|
+
unexpose,
|
|
309
412
|
async call(exportName, method, input, caller) {
|
|
310
413
|
const state = target(exportName, "rpc");
|
|
311
414
|
const spec = own(state.iface.methods, method);
|
|
@@ -552,13 +655,7 @@ function runFrame(options) {
|
|
|
552
655
|
log.error("The frame couldn't handle a message from the shell.", { error: String(error) });
|
|
553
656
|
}
|
|
554
657
|
};
|
|
555
|
-
let told;
|
|
556
658
|
return {
|
|
557
|
-
size(height) {
|
|
558
|
-
if (!mounted || height === told) return;
|
|
559
|
-
told = height;
|
|
560
|
-
send({ op: "size", height });
|
|
561
|
-
},
|
|
562
659
|
failed(error) {
|
|
563
660
|
log.error(error instanceof Error ? error.message : String(error), {
|
|
564
661
|
...error instanceof Error && error.stack ? { stack: error.stack } : {}
|
|
@@ -573,9 +670,71 @@ function runFrame(options) {
|
|
|
573
670
|
};
|
|
574
671
|
}
|
|
575
672
|
|
|
673
|
+
// src/frame-base.ts
|
|
674
|
+
var FRAME_BASE = `
|
|
675
|
+
:where(*, *::before, *::after) { box-sizing: border-box; }
|
|
676
|
+
:where(html, body) { height: 100%; margin: 0; background: transparent; }
|
|
677
|
+
:where(body) {
|
|
678
|
+
overflow: auto; scrollbar-width: none;
|
|
679
|
+
color: var(--fg); font: 14px/1.45 var(--font, ui-sans-serif, system-ui, sans-serif);
|
|
680
|
+
-webkit-font-smoothing: antialiased;
|
|
681
|
+
}
|
|
682
|
+
:where(body)::-webkit-scrollbar { display: none; }
|
|
683
|
+
:where(body > :only-child) { min-height: 100%; }
|
|
684
|
+
:where(h1, h2, h3, h4) { margin: 0 0 8px; font-weight: 600; letter-spacing: -0.01em; }
|
|
685
|
+
:where(h1) { font-size: 20px; }
|
|
686
|
+
:where(h2) { font-size: 16px; }
|
|
687
|
+
:where(h3, h4) { font-size: 14px; }
|
|
688
|
+
:where(p) { margin: 0 0 8px; }
|
|
689
|
+
:where(small) { color: var(--muted); font-size: 12.5px; }
|
|
690
|
+
:where(a) { color: inherit; text-underline-offset: 2px; }
|
|
691
|
+
:where(hr) { border: 0; border-top: 1px solid var(--line); margin: 10px 0; }
|
|
692
|
+
:where(ul, ol) { margin: 0 0 10px; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 6px; }
|
|
693
|
+
:where(li) { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 10px; background: var(--raised); }
|
|
694
|
+
:where(button) {
|
|
695
|
+
height: 34px; padding: 0 12px; border: 0; border-radius: 9px; cursor: pointer;
|
|
696
|
+
background: var(--hover); color: var(--fg); font: inherit; font-weight: 500;
|
|
697
|
+
}
|
|
698
|
+
:where(button:hover) { background: var(--selected); }
|
|
699
|
+
:where(button:disabled) { opacity: 0.5; cursor: default; }
|
|
700
|
+
:where(button[type="submit"], button.primary) { background: var(--accent); color: var(--accent-fg); font-weight: 600; }
|
|
701
|
+
:where(input:not([type]), input[type="text"], input[type="search"], input[type="number"], input[type="url"], input[type="email"], select) {
|
|
702
|
+
height: 34px; padding: 0 10px; border: 0; border-radius: 9px; outline: 0;
|
|
703
|
+
background: var(--raised); color: var(--fg); font: inherit;
|
|
704
|
+
}
|
|
705
|
+
:where(textarea) { padding: 8px 10px; border: 0; border-radius: 9px; outline: 0; resize: none; background: var(--raised); color: var(--fg); font: inherit; }
|
|
706
|
+
:where(input:focus-visible, textarea:focus-visible, select:focus-visible, button:focus-visible) { box-shadow: 0 0 0 1.5px var(--ring); outline: 0; }
|
|
707
|
+
:where(input[type="checkbox"]) {
|
|
708
|
+
appearance: none; width: 16px; height: 16px; margin: 0; flex: none; display: grid; place-items: center;
|
|
709
|
+
border: 1.5px solid var(--faint); border-radius: 5px; cursor: pointer;
|
|
710
|
+
}
|
|
711
|
+
:where(input[type="checkbox"]:checked) { background: var(--ok); border-color: var(--ok); }
|
|
712
|
+
:where(input[type="checkbox"]:checked)::after {
|
|
713
|
+
content: ""; width: 4px; height: 8px; border: solid white; border-width: 0 2px 2px 0;
|
|
714
|
+
transform: translateY(-1px) rotate(45deg);
|
|
715
|
+
}
|
|
716
|
+
:where(li:has(> input[type="checkbox"]:checked) > span) { color: var(--faint); text-decoration: line-through; }
|
|
717
|
+
:where(form) { display: flex; gap: 6px; }
|
|
718
|
+
:where(form > input, form > textarea) { flex: 1; min-width: 0; }
|
|
719
|
+
:where(table) { width: 100%; border-collapse: collapse; font-size: 13px; }
|
|
720
|
+
:where(th) { padding: 0 8px 6px; text-align: left; color: var(--faint); font-weight: 500; font-size: 12px; }
|
|
721
|
+
:where(td) { padding: 7px 8px; border-top: 1px solid var(--line); }
|
|
722
|
+
:where(code, pre) { font: 12.5px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
723
|
+
:where(code) { padding: 1px 5px; border-radius: 5px; background: var(--raised); }
|
|
724
|
+
:where(pre) { margin: 0 0 10px; padding: 10px 12px; border-radius: 10px; background: var(--raised); overflow: auto; }
|
|
725
|
+
:where(pre code) { padding: 0; background: none; }
|
|
726
|
+
:where(progress) { appearance: none; width: 100%; height: 4px; border: 0; border-radius: 2px; background: var(--raised); }
|
|
727
|
+
:where(progress)::-webkit-progress-bar { background: var(--raised); border-radius: 2px; }
|
|
728
|
+
:where(progress)::-webkit-progress-value { background: var(--ok); border-radius: 2px; }
|
|
729
|
+
:where(progress)::-moz-progress-bar { background: var(--ok); border-radius: 2px; }
|
|
730
|
+
`;
|
|
731
|
+
|
|
576
732
|
// src/frame-entry.ts
|
|
577
733
|
var self = globalThis;
|
|
578
734
|
var frame;
|
|
735
|
+
var base = self.document.createElement("style");
|
|
736
|
+
base.textContent = FRAME_BASE;
|
|
737
|
+
self.document.head.prepend(base);
|
|
579
738
|
self.addEventListener("message", (event) => {
|
|
580
739
|
const port = event.ports[0];
|
|
581
740
|
if (frame || event.source !== self.parent || event.data !== FRAME_HELLO || !port) return;
|
|
@@ -589,10 +748,6 @@ self.addEventListener("message", (event) => {
|
|
|
589
748
|
if (name.startsWith("--")) self.document.documentElement.style.setProperty(name, value);
|
|
590
749
|
}
|
|
591
750
|
});
|
|
592
|
-
const body = self.document.body;
|
|
593
|
-
new self.ResizeObserver(
|
|
594
|
-
() => frame?.size(Math.ceil(body.getBoundingClientRect().height))
|
|
595
|
-
).observe(body);
|
|
596
751
|
});
|
|
597
752
|
self.addEventListener("error", (event) => frame?.failed(event.error ?? event.message));
|
|
598
753
|
self.addEventListener("unhandledrejection", (event) => frame?.failed(event.reason));
|
|
@@ -478,10 +478,27 @@ function parseHeader(value) {
|
|
|
478
478
|
return { op: "offer", name: text(value, "name"), interface: value.interface };
|
|
479
479
|
case "withdraw":
|
|
480
480
|
return { op: "withdraw", name: text(value, "name") };
|
|
481
|
-
case "slot":
|
|
481
|
+
case "slot": {
|
|
482
482
|
if (typeof value.bound !== "boolean")
|
|
483
483
|
throw new HeaderError("A slot header needs bound.");
|
|
484
|
-
|
|
484
|
+
if (!("exposed" in value))
|
|
485
|
+
return { op: "slot", name: text(value, "name"), bound: value.bound };
|
|
486
|
+
const exposed = value.exposed;
|
|
487
|
+
if (!value.bound || !isRecord(exposed) || !isRecord(exposed.interface) || !isRecord(exposed.provider))
|
|
488
|
+
throw new HeaderError("A slot header's exposed is a bound slot's {interface, provider}.");
|
|
489
|
+
return {
|
|
490
|
+
op: "slot",
|
|
491
|
+
name: text(value, "name"),
|
|
492
|
+
bound: true,
|
|
493
|
+
exposed: {
|
|
494
|
+
interface: exposed.interface,
|
|
495
|
+
provider: {
|
|
496
|
+
actor: text(exposed.provider, "actor"),
|
|
497
|
+
export: text(exposed.provider, "export")
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
}
|
|
485
502
|
case "serve": {
|
|
486
503
|
const kind = value.kind;
|
|
487
504
|
if (kind !== "call" && kind !== "subscribe" && kind !== "open" && kind !== "http")
|
|
@@ -21113,6 +21130,24 @@ var ModuleHost = class {
|
|
|
21113
21130
|
);
|
|
21114
21131
|
this.#resubscribe(slot);
|
|
21115
21132
|
}
|
|
21133
|
+
/**
|
|
21134
|
+
* A notice for a slot made at run time: bound (or usable again) with its exposure, or gone. Its
|
|
21135
|
+
* name is the Actor's, with no module prefix: every module of the Actor has it.
|
|
21136
|
+
*/
|
|
21137
|
+
onExposed(slot, exposure) {
|
|
21138
|
+
if (!this.#channel) return;
|
|
21139
|
+
if (!exposure) {
|
|
21140
|
+
this.runtime.unexpose(slot);
|
|
21141
|
+
return;
|
|
21142
|
+
}
|
|
21143
|
+
const open2 = this.#channel;
|
|
21144
|
+
this.runtime.expose(slot, {
|
|
21145
|
+
described: exposure.interface,
|
|
21146
|
+
provider: exposure.provider,
|
|
21147
|
+
call: (method, value) => open2.call(slot, method, value),
|
|
21148
|
+
subscribe: (event, onEvent, onEnd) => open2.subscribe(slot, event, onEvent, () => onEnd())
|
|
21149
|
+
});
|
|
21150
|
+
}
|
|
21116
21151
|
/** How this module serves the Hub's streams, by its local export names. */
|
|
21117
21152
|
serve = {
|
|
21118
21153
|
call: (serve, value) => this.runtime.call(serve.export, serve.method ?? "", value, serve.caller),
|
|
@@ -21153,9 +21188,12 @@ var ModuleHost = class {
|
|
|
21153
21188
|
this.#channel = channel2;
|
|
21154
21189
|
for (const [name, { handle, iface }] of this.#added) this.#offer(channel2, name, iface, handle);
|
|
21155
21190
|
for (const name of channel2.bound)
|
|
21156
|
-
if (name.startsWith(this.#prefix)
|
|
21191
|
+
if (name.startsWith(this.#prefix) && !channel2.exposed.has(name))
|
|
21192
|
+
this.onSlot(name.slice(this.#prefix.length), true);
|
|
21193
|
+
for (const [name, exposure] of channel2.exposed) this.onExposed(name, exposure);
|
|
21157
21194
|
void channel2.closed.then(() => {
|
|
21158
21195
|
for (const slot of [...this.#bindings.keys()]) this.onSlot(slot, false);
|
|
21196
|
+
for (const { slot } of this.runtime.ctx.exposed()) this.runtime.unexpose(slot);
|
|
21159
21197
|
for (const ends of this.#subscribers.values()) for (const end of [...ends]) end();
|
|
21160
21198
|
});
|
|
21161
21199
|
}
|
|
@@ -21303,6 +21341,102 @@ function createRuntime(definition, options) {
|
|
|
21303
21341
|
throw new Refused("unimplemented", `${name} hasn't been implemented yet.`);
|
|
21304
21342
|
return state.impl;
|
|
21305
21343
|
};
|
|
21344
|
+
const exposed = /* @__PURE__ */ new Map();
|
|
21345
|
+
const exposedWatchers = /* @__PURE__ */ new Set();
|
|
21346
|
+
const exposedChanged = () => {
|
|
21347
|
+
const failed = (error62) => options.log.error("An onExposed handler threw.", { error: String(error62) });
|
|
21348
|
+
for (const fn of [...exposedWatchers])
|
|
21349
|
+
try {
|
|
21350
|
+
const done = fn();
|
|
21351
|
+
if (done instanceof Promise) done.catch(failed);
|
|
21352
|
+
} catch (error62) {
|
|
21353
|
+
failed(error62);
|
|
21354
|
+
}
|
|
21355
|
+
};
|
|
21356
|
+
const listenExposed = (slot, state, event) => {
|
|
21357
|
+
const entry = state.events.get(event);
|
|
21358
|
+
if (state.gone || !entry || entry.stop || !entry.fns.size) return;
|
|
21359
|
+
let ended = false;
|
|
21360
|
+
let stop;
|
|
21361
|
+
stop = state.source.subscribe(
|
|
21362
|
+
event,
|
|
21363
|
+
(payload) => {
|
|
21364
|
+
for (const fn of [...entry.fns])
|
|
21365
|
+
try {
|
|
21366
|
+
fn(payload);
|
|
21367
|
+
} catch (error62) {
|
|
21368
|
+
options.log.error("An event handler threw.", { slot, event, error: String(error62) });
|
|
21369
|
+
}
|
|
21370
|
+
},
|
|
21371
|
+
// Ended by the provider going: the interest stays for when it is usable again.
|
|
21372
|
+
() => {
|
|
21373
|
+
ended = true;
|
|
21374
|
+
if (entry.stop === stop) entry.stop = void 0;
|
|
21375
|
+
}
|
|
21376
|
+
);
|
|
21377
|
+
if (!ended) entry.stop = stop;
|
|
21378
|
+
};
|
|
21379
|
+
const exposedHandle = (slot, state) => {
|
|
21380
|
+
const { described, provider } = state.source;
|
|
21381
|
+
return Object.freeze({
|
|
21382
|
+
slot,
|
|
21383
|
+
described,
|
|
21384
|
+
provider: Object.freeze({ actor: provider.actor, export: provider.export }),
|
|
21385
|
+
call: Object.freeze(
|
|
21386
|
+
Object.fromEntries(
|
|
21387
|
+
(described.kind === "rpc" ? Object.keys(described.methods) : []).map((method) => [
|
|
21388
|
+
method,
|
|
21389
|
+
async (input3) => {
|
|
21390
|
+
if (state.gone) throw new NotConnected(slot);
|
|
21391
|
+
return state.source.call(method, input3);
|
|
21392
|
+
}
|
|
21393
|
+
])
|
|
21394
|
+
)
|
|
21395
|
+
),
|
|
21396
|
+
on(event, fn) {
|
|
21397
|
+
if (described.kind !== "rpc" || !own2(described.events, event))
|
|
21398
|
+
throw new TypeError(`${slot} has no event ${event}.`);
|
|
21399
|
+
const entry = state.events.get(event) ?? { fns: /* @__PURE__ */ new Set() };
|
|
21400
|
+
state.events.set(event, entry);
|
|
21401
|
+
entry.fns.add(fn);
|
|
21402
|
+
listenExposed(slot, state, event);
|
|
21403
|
+
return () => {
|
|
21404
|
+
entry.fns.delete(fn);
|
|
21405
|
+
if (entry.fns.size) return;
|
|
21406
|
+
entry.stop?.();
|
|
21407
|
+
entry.stop = void 0;
|
|
21408
|
+
};
|
|
21409
|
+
}
|
|
21410
|
+
});
|
|
21411
|
+
};
|
|
21412
|
+
const unexpose = (slot) => {
|
|
21413
|
+
const state = exposed.get(slot);
|
|
21414
|
+
if (!state) return;
|
|
21415
|
+
exposed.delete(slot);
|
|
21416
|
+
state.gone = true;
|
|
21417
|
+
for (const entry of state.events.values()) {
|
|
21418
|
+
entry.stop?.();
|
|
21419
|
+
entry.stop = void 0;
|
|
21420
|
+
}
|
|
21421
|
+
exposedChanged();
|
|
21422
|
+
};
|
|
21423
|
+
const expose = (slot, source) => {
|
|
21424
|
+
const here = exposed.get(slot);
|
|
21425
|
+
if (here && here.source.described.hash === source.described.hash && here.source.provider.actor === source.provider.actor && here.source.provider.export === source.provider.export) {
|
|
21426
|
+
here.source = source;
|
|
21427
|
+
for (const [event, entry] of here.events) {
|
|
21428
|
+
entry.stop?.();
|
|
21429
|
+
entry.stop = void 0;
|
|
21430
|
+
listenExposed(slot, here, event);
|
|
21431
|
+
}
|
|
21432
|
+
return;
|
|
21433
|
+
}
|
|
21434
|
+
if (here) unexpose(slot);
|
|
21435
|
+
const state = { source, gone: false, events: /* @__PURE__ */ new Map() };
|
|
21436
|
+
state.handle = exposedHandle(slot, state);
|
|
21437
|
+
exposed.set(slot, state);
|
|
21438
|
+
exposedChanged();
|
|
21439
|
+
};
|
|
21306
21440
|
const ctx = {
|
|
21307
21441
|
slots: Object.fromEntries(
|
|
21308
21442
|
Object.entries(definition.slots).map(([name, iface]) => [name, slotHandle(name, iface)])
|
|
@@ -21328,7 +21462,12 @@ function createRuntime(definition, options) {
|
|
|
21328
21462
|
}
|
|
21329
21463
|
),
|
|
21330
21464
|
self: options.self,
|
|
21331
|
-
log: options.log
|
|
21465
|
+
log: options.log,
|
|
21466
|
+
exposed: () => Object.freeze([...exposed.values()].map((state) => state.handle)),
|
|
21467
|
+
onExposed(fn) {
|
|
21468
|
+
exposedWatchers.add(fn);
|
|
21469
|
+
return () => void exposedWatchers.delete(fn);
|
|
21470
|
+
}
|
|
21332
21471
|
};
|
|
21333
21472
|
const serving = (exportName) => {
|
|
21334
21473
|
const state = target(exportName, "http");
|
|
@@ -21395,6 +21534,8 @@ function createRuntime(definition, options) {
|
|
|
21395
21534
|
if (!state) throw new TypeError(`No slot ${slot}.`);
|
|
21396
21535
|
if (state.binding) notify(slot, state.binds);
|
|
21397
21536
|
},
|
|
21537
|
+
expose,
|
|
21538
|
+
unexpose,
|
|
21398
21539
|
async call(exportName, method, input3, caller) {
|
|
21399
21540
|
const state = target(exportName, "rpc");
|
|
21400
21541
|
const spec = own2(state.iface.methods, method);
|
|
@@ -21478,6 +21619,8 @@ var drain = (reader) => void reader.rest().pipeTo(new WritableStream()).catch(()
|
|
|
21478
21619
|
async function openChannel(options) {
|
|
21479
21620
|
let session;
|
|
21480
21621
|
const bound = /* @__PURE__ */ new Set();
|
|
21622
|
+
const exposed = /* @__PURE__ */ new Map();
|
|
21623
|
+
let ended = false;
|
|
21481
21624
|
let ready;
|
|
21482
21625
|
let headers = new Promise((resolve) => {
|
|
21483
21626
|
ready = resolve;
|
|
@@ -21503,12 +21646,17 @@ async function openChannel(options) {
|
|
|
21503
21646
|
}
|
|
21504
21647
|
async function serveStream(header, stream, reader) {
|
|
21505
21648
|
if (header.op === "slot") {
|
|
21649
|
+
if (ended) return;
|
|
21506
21650
|
if (header.bound) bound.add(header.name);
|
|
21507
21651
|
else bound.delete(header.name);
|
|
21508
|
-
|
|
21652
|
+
const wasExposed = exposed.delete(header.name);
|
|
21653
|
+
const exposure = header.exposed;
|
|
21654
|
+
if (exposure) exposed.set(header.name, exposure);
|
|
21655
|
+
void stream.writable.close().catch(() => {
|
|
21509
21656
|
});
|
|
21510
21657
|
try {
|
|
21511
|
-
options.
|
|
21658
|
+
if (exposure || wasExposed) options.onExposed?.(header.name, exposure);
|
|
21659
|
+
else options.onSlot?.(header.name, header.bound);
|
|
21512
21660
|
} catch (error62) {
|
|
21513
21661
|
options.log?.error("A slot notice's handler threw.", {
|
|
21514
21662
|
slot: header.name,
|
|
@@ -21622,18 +21770,23 @@ async function openChannel(options) {
|
|
|
21622
21770
|
});
|
|
21623
21771
|
return next;
|
|
21624
21772
|
};
|
|
21625
|
-
const closed = session.closed.then(() =>
|
|
21773
|
+
const closed = session.closed.then(() => {
|
|
21774
|
+
ended = true;
|
|
21775
|
+
bound.clear();
|
|
21776
|
+
exposed.clear();
|
|
21777
|
+
});
|
|
21626
21778
|
return {
|
|
21627
21779
|
actorId: options.actorId,
|
|
21628
21780
|
bound,
|
|
21781
|
+
exposed,
|
|
21629
21782
|
async call(slot, method, value) {
|
|
21630
21783
|
return answered(await exchange({ op: "call", slot, method }, slot, input(value)), slot);
|
|
21631
21784
|
},
|
|
21632
21785
|
subscribe(slot, event, onEvent, onEnd) {
|
|
21633
|
-
let
|
|
21786
|
+
let ended2 = false;
|
|
21634
21787
|
const end = (error62) => {
|
|
21635
|
-
if (
|
|
21636
|
-
|
|
21788
|
+
if (ended2) return;
|
|
21789
|
+
ended2 = true;
|
|
21637
21790
|
onEnd?.(error62);
|
|
21638
21791
|
};
|
|
21639
21792
|
let stream;
|
|
@@ -21662,7 +21815,7 @@ async function openChannel(options) {
|
|
|
21662
21815
|
}
|
|
21663
21816
|
})();
|
|
21664
21817
|
return () => {
|
|
21665
|
-
|
|
21818
|
+
ended2 = true;
|
|
21666
21819
|
stream.reset();
|
|
21667
21820
|
};
|
|
21668
21821
|
},
|
|
@@ -21738,6 +21891,10 @@ async function runHost(options) {
|
|
|
21738
21891
|
const found = route(name);
|
|
21739
21892
|
found?.[0].onSlot(found[1], bound);
|
|
21740
21893
|
},
|
|
21894
|
+
// A slot made at run time is the Actor's: every host module has it.
|
|
21895
|
+
onExposed(name, exposure) {
|
|
21896
|
+
for (const host2 of hosts.values()) host2.onExposed(name, exposure);
|
|
21897
|
+
},
|
|
21741
21898
|
serve: {
|
|
21742
21899
|
call: (serve, value) => {
|
|
21743
21900
|
const [handlers, local] = routed(serve);
|
|
@@ -47,14 +47,32 @@ interface ChannelBase {
|
|
|
47
47
|
* or, for a slot already bound, when its provider came back.
|
|
48
48
|
*/
|
|
49
49
|
onSlot?(name: string, bound: boolean): void;
|
|
50
|
+
/**
|
|
51
|
+
* Each notice for a slot made at run time, in the same order: its exposure when bound (or
|
|
52
|
+
* usable again), `undefined` when it is gone. These don't reach `onSlot`.
|
|
53
|
+
*/
|
|
54
|
+
onExposed?(name: string, exposure: ChannelExposure | undefined): void;
|
|
50
55
|
/** Where a notice handler's own failure is reported. */
|
|
51
56
|
log?: Log;
|
|
52
57
|
}
|
|
58
|
+
/** A slot made at run time, as the channel keeps it: the export's interface, and whose it is. */
|
|
59
|
+
export interface ChannelExposure {
|
|
60
|
+
interface: DescribedInterface;
|
|
61
|
+
provider: {
|
|
62
|
+
actor: string;
|
|
63
|
+
export: string;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
53
66
|
/** A channel to the Hub as one Actor, at the wire's level: no local checks, no handles. */
|
|
54
67
|
export interface Channel {
|
|
55
68
|
readonly actorId: string;
|
|
56
69
|
/** The Actor's slots bound now, from hello's snapshot and the Hub's notices; empty once closed. */
|
|
57
70
|
readonly bound: ReadonlySet<string>;
|
|
71
|
+
/**
|
|
72
|
+
* The slots made for it at run time and bound now, from the notices: hello names them among
|
|
73
|
+
* `bound`, and a notice with each one's exposure follows.
|
|
74
|
+
*/
|
|
75
|
+
readonly exposed: ReadonlyMap<string, ChannelExposure>;
|
|
58
76
|
call(slot: string, method: string, value: unknown): Promise<unknown>;
|
|
59
77
|
/** Events from a slot's provider until it ends (`onEnd`) or is stopped; returns how to stop. */
|
|
60
78
|
subscribe(slot: string, event: string, onEvent: (payload: unknown) => void, onEnd?: (error?: Error) => void): () => void;
|
|
@@ -48,6 +48,9 @@ const drain = (reader) => void reader
|
|
|
48
48
|
export async function openChannel(options) {
|
|
49
49
|
let session;
|
|
50
50
|
const bound = new Set();
|
|
51
|
+
const exposed = new Map();
|
|
52
|
+
/** Set as the session ends: a notice read before then but handled after is dropped. */
|
|
53
|
+
let ended = false;
|
|
51
54
|
// Notices arrive as streams; their headers are read in arrival order, after hello's snapshot.
|
|
52
55
|
let ready;
|
|
53
56
|
let headers = new Promise((resolve) => {
|
|
@@ -74,13 +77,25 @@ export async function openChannel(options) {
|
|
|
74
77
|
}
|
|
75
78
|
async function serveStream(header, stream, reader) {
|
|
76
79
|
if (header.op === "slot") {
|
|
80
|
+
if (ended)
|
|
81
|
+
return;
|
|
77
82
|
if (header.bound)
|
|
78
83
|
bound.add(header.name);
|
|
79
84
|
else
|
|
80
85
|
bound.delete(header.name);
|
|
81
|
-
|
|
86
|
+
// A slot made at run time is its exposure while bound, and gone when unbound.
|
|
87
|
+
const wasExposed = exposed.delete(header.name);
|
|
88
|
+
const exposure = header.exposed;
|
|
89
|
+
if (exposure)
|
|
90
|
+
exposed.set(header.name, exposure);
|
|
91
|
+
// Told before closing our side, which may wait behind other frames: a channel that ends
|
|
92
|
+
// meanwhile must not hear of a slot after its close has cleared them.
|
|
93
|
+
void stream.writable.close().catch(() => { });
|
|
82
94
|
try {
|
|
83
|
-
|
|
95
|
+
if (exposure || wasExposed)
|
|
96
|
+
options.onExposed?.(header.name, exposure);
|
|
97
|
+
else
|
|
98
|
+
options.onSlot?.(header.name, header.bound);
|
|
84
99
|
}
|
|
85
100
|
catch (error) {
|
|
86
101
|
options.log?.error("A slot notice's handler threw.", {
|
|
@@ -205,10 +220,15 @@ export async function openChannel(options) {
|
|
|
205
220
|
changes = next.catch(() => { });
|
|
206
221
|
return next;
|
|
207
222
|
};
|
|
208
|
-
const closed = session.closed.then(() =>
|
|
223
|
+
const closed = session.closed.then(() => {
|
|
224
|
+
ended = true;
|
|
225
|
+
bound.clear();
|
|
226
|
+
exposed.clear();
|
|
227
|
+
});
|
|
209
228
|
return {
|
|
210
229
|
actorId: options.actorId,
|
|
211
230
|
bound,
|
|
231
|
+
exposed,
|
|
212
232
|
async call(slot, method, value) {
|
|
213
233
|
return answered(await exchange({ op: "call", slot, method }, slot, input(value)), slot);
|
|
214
234
|
},
|
|
@@ -325,6 +345,7 @@ export async function connect(options) {
|
|
|
325
345
|
? {}
|
|
326
346
|
: { declares: { slots: describeAll(slots), exports: describeAll(exports) } }),
|
|
327
347
|
onSlot: (slot, bound) => host.onSlot(slot, bound),
|
|
348
|
+
onExposed: (slot, exposure) => host.onExposed(slot, exposure),
|
|
328
349
|
serve: host.serve,
|
|
329
350
|
});
|
|
330
351
|
host.attach(channel);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The base stylesheet every view's frame gets first, before the view's own: the document fills the
|
|
3
|
+
* frame on a transparent background, and plain HTML looks like the shell, drawn with the theme's
|
|
4
|
+
* tokens (`--fg`, `--surface`, `--accent`, … as the shell sends them at mount). Every rule is in
|
|
5
|
+
* `:where()`, so it has no specificity: any selector a view writes wins, and a view that wants its
|
|
6
|
+
* own look draws it.
|
|
7
|
+
*/
|
|
8
|
+
export declare const FRAME_BASE = "\n:where(*, *::before, *::after) { box-sizing: border-box; }\n:where(html, body) { height: 100%; margin: 0; background: transparent; }\n:where(body) {\n overflow: auto; scrollbar-width: none;\n color: var(--fg); font: 14px/1.45 var(--font, ui-sans-serif, system-ui, sans-serif);\n -webkit-font-smoothing: antialiased;\n}\n:where(body)::-webkit-scrollbar { display: none; }\n:where(body > :only-child) { min-height: 100%; }\n:where(h1, h2, h3, h4) { margin: 0 0 8px; font-weight: 600; letter-spacing: -0.01em; }\n:where(h1) { font-size: 20px; }\n:where(h2) { font-size: 16px; }\n:where(h3, h4) { font-size: 14px; }\n:where(p) { margin: 0 0 8px; }\n:where(small) { color: var(--muted); font-size: 12.5px; }\n:where(a) { color: inherit; text-underline-offset: 2px; }\n:where(hr) { border: 0; border-top: 1px solid var(--line); margin: 10px 0; }\n:where(ul, ol) { margin: 0 0 10px; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 6px; }\n:where(li) { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 10px; background: var(--raised); }\n:where(button) {\n height: 34px; padding: 0 12px; border: 0; border-radius: 9px; cursor: pointer;\n background: var(--hover); color: var(--fg); font: inherit; font-weight: 500;\n}\n:where(button:hover) { background: var(--selected); }\n:where(button:disabled) { opacity: 0.5; cursor: default; }\n:where(button[type=\"submit\"], button.primary) { background: var(--accent); color: var(--accent-fg); font-weight: 600; }\n:where(input:not([type]), input[type=\"text\"], input[type=\"search\"], input[type=\"number\"], input[type=\"url\"], input[type=\"email\"], select) {\n height: 34px; padding: 0 10px; border: 0; border-radius: 9px; outline: 0;\n background: var(--raised); color: var(--fg); font: inherit;\n}\n:where(textarea) { padding: 8px 10px; border: 0; border-radius: 9px; outline: 0; resize: none; background: var(--raised); color: var(--fg); font: inherit; }\n:where(input:focus-visible, textarea:focus-visible, select:focus-visible, button:focus-visible) { box-shadow: 0 0 0 1.5px var(--ring); outline: 0; }\n:where(input[type=\"checkbox\"]) {\n appearance: none; width: 16px; height: 16px; margin: 0; flex: none; display: grid; place-items: center;\n border: 1.5px solid var(--faint); border-radius: 5px; cursor: pointer;\n}\n:where(input[type=\"checkbox\"]:checked) { background: var(--ok); border-color: var(--ok); }\n:where(input[type=\"checkbox\"]:checked)::after {\n content: \"\"; width: 4px; height: 8px; border: solid white; border-width: 0 2px 2px 0;\n transform: translateY(-1px) rotate(45deg);\n}\n:where(li:has(> input[type=\"checkbox\"]:checked) > span) { color: var(--faint); text-decoration: line-through; }\n:where(form) { display: flex; gap: 6px; }\n:where(form > input, form > textarea) { flex: 1; min-width: 0; }\n:where(table) { width: 100%; border-collapse: collapse; font-size: 13px; }\n:where(th) { padding: 0 8px 6px; text-align: left; color: var(--faint); font-weight: 500; font-size: 12px; }\n:where(td) { padding: 7px 8px; border-top: 1px solid var(--line); }\n:where(code, pre) { font: 12.5px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace; }\n:where(code) { padding: 1px 5px; border-radius: 5px; background: var(--raised); }\n:where(pre) { margin: 0 0 10px; padding: 10px 12px; border-radius: 10px; background: var(--raised); overflow: auto; }\n:where(pre code) { padding: 0; background: none; }\n:where(progress) { appearance: none; width: 100%; height: 4px; border: 0; border-radius: 2px; background: var(--raised); }\n:where(progress)::-webkit-progress-bar { background: var(--raised); border-radius: 2px; }\n:where(progress)::-webkit-progress-value { background: var(--ok); border-radius: 2px; }\n:where(progress)::-moz-progress-bar { background: var(--ok); border-radius: 2px; }\n";
|