Mirror orbit.server into the sandbox via the state snapshot
This commit is contained in:
parent
71dd987fb5
commit
fa115e5bc3
4 changed files with 30 additions and 5 deletions
|
|
@ -45,8 +45,11 @@ The sandboxed API (`src/modules/sandbox/host.ts` + `public/plugin-sandbox.html`)
|
||||||
`orbit.log`, `orbit.on(event, fn)` (forwarded `connected` / `message` /
|
`orbit.log`, `orbit.on(event, fn)` (forwarded `connected` / `message` /
|
||||||
`buffer.active` / `status`), `orbit.irc.*`, `orbit.notify`,
|
`buffer.active` / `status`), `orbit.irc.*`, `orbit.notify`,
|
||||||
`orbit.state.active/nick/account/buffers` (from a pushed snapshot, synchronous),
|
`orbit.state.active/nick/account/buffers` (from a pushed snapshot, synchronous),
|
||||||
`orbit.storage.get/set`, and `orbit.ui(slot, build)` where `build(el)` populates the
|
`orbit.server.network/isupport/hasCap/caps` (also from the snapshot, synchronous —
|
||||||
plugin's own iframe and the host sizes the frame to the content.
|
gate cap-dependent behaviour so a plugin never 421s a lean server; no `numeric()`
|
||||||
|
here since the sandbox gets no `raw` events), `orbit.storage.get/set`, and
|
||||||
|
`orbit.ui(slot, build)` where `build(el)` populates the plugin's own iframe and the
|
||||||
|
host sizes the frame to the content.
|
||||||
|
|
||||||
The app's theme CSS vars (`--bg`, `--ink`, `--accent`, `--muted`, `--border`,
|
The app's theme CSS vars (`--bg`, `--ink`, `--accent`, `--muted`, `--border`,
|
||||||
`--panel`, `--green-soft`) are mirrored into the sandbox and kept in sync on theme
|
`--panel`, `--green-soft`) are mirrored into the sandbox and kept in sync on theme
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
* served with its own strict CSP.
|
* served with its own strict CSP.
|
||||||
*/
|
*/
|
||||||
(function () {
|
(function () {
|
||||||
var port, snap = { active: '', nick: '', account: '', buffers: [] }, store = {};
|
var port, snap = { active: '', nick: '', account: '', buffers: [], network: '', isupport: {}, caps: [] }, store = {};
|
||||||
var listeners = {}; // event name -> [fn]
|
var listeners = {}; // event name -> [fn]
|
||||||
var pending = new Map(), rpcId = 0; // in-flight RPCs
|
var pending = new Map(), rpcId = 0; // in-flight RPCs
|
||||||
|
|
||||||
|
|
@ -87,6 +87,13 @@
|
||||||
account: function () { return snap.account; },
|
account: function () { return snap.account; },
|
||||||
buffers: function () { return snap.buffers.slice(); },
|
buffers: function () { return snap.buffers.slice(); },
|
||||||
},
|
},
|
||||||
|
// Read-only server / capability info, from the snapshot (no RPC, no grant).
|
||||||
|
server: {
|
||||||
|
network: function () { return snap.network || ''; },
|
||||||
|
isupport: function () { var o = {}, m = snap.isupport || {}, k; for (k in m) o[k] = m[k]; return o; },
|
||||||
|
hasCap: function (cap) { return (snap.caps || []).some(function (c) { return c.name === cap && c.enabled; }); },
|
||||||
|
caps: function () { return (snap.caps || []).map(function (c) { return { name: c.name, available: c.available, enabled: c.enabled }; }); },
|
||||||
|
},
|
||||||
storage: {
|
storage: {
|
||||||
get: function (k, fallback) { return k in store ? store[k] : fallback; },
|
get: function (k, fallback) { return k in store ? store[k] : fallback; },
|
||||||
set: function (k, v) { store[k] = v; return rpc('storage.set', k, v); },
|
set: function (k, v) { store[k] = v; return rpc('storage.set', k, v); },
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,13 @@ const STORE_PREFIX = 'orbit-sbx:';
|
||||||
|
|
||||||
function snapshot(): StateSnapshot {
|
function snapshot(): StateSnapshot {
|
||||||
const s = activeStore().getState();
|
const s = activeStore().getState();
|
||||||
return { active: s.active, nick: s.nick, account: s.account, buffers: Object.keys(s.buffers) };
|
const cl = s.client;
|
||||||
|
return {
|
||||||
|
active: s.active, nick: s.nick, account: s.account, buffers: Object.keys(s.buffers),
|
||||||
|
network: cl?.server.network ?? '',
|
||||||
|
isupport: { ...(cl?.server.isupport ?? {}) },
|
||||||
|
caps: cl?.ircv3.listCaps() ?? [],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current values of the app's themeable CSS vars, mirrored into the sandbox.
|
// Current values of the app's themeable CSS vars, mirrored into the sandbox.
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,16 @@ export const THEME_VARS = ['--bg', '--ink', '--accent', '--muted', '--border', '
|
||||||
// guest -> host
|
// guest -> host
|
||||||
export interface RpcMsg { type: 'rpc'; id: number; method: string; args: unknown[]; }
|
export interface RpcMsg { type: 'rpc'; id: number; method: string; args: unknown[]; }
|
||||||
|
|
||||||
export interface StateSnapshot { active: string; nick: string; account: string; buffers: string[]; }
|
export interface StateSnapshot {
|
||||||
|
active: string; nick: string; account: string; buffers: string[];
|
||||||
|
// Read-only server / capability info (client.server + client.ircv3), pushed in the
|
||||||
|
// snapshot so a sandboxed plugin can gate cap-dependent behaviour synchronously —
|
||||||
|
// never a raw command that 421s a lean server. (No numeric map: the sandbox gets
|
||||||
|
// no 'raw' events, so there are no numeric replies to name.)
|
||||||
|
network: string;
|
||||||
|
isupport: Record<string, string>;
|
||||||
|
caps: { name: string; available: boolean; enabled: boolean }[];
|
||||||
|
}
|
||||||
|
|
||||||
export type HostToGuest = InitMsg | EventMsg | SnapshotMsg | ThemeMsg | RpcReplyMsg;
|
export type HostToGuest = InitMsg | EventMsg | SnapshotMsg | ThemeMsg | RpcReplyMsg;
|
||||||
export type GuestToHost = RpcMsg;
|
export type GuestToHost = RpcMsg;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue