Publish Vulpes Preview 15 sources for desktop, Android and Tundra

Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
This commit is contained in:
OverSu 2026-09-30 23:13:03 +02:00
commit b38dea0597
25901 changed files with 9982925 additions and 369 deletions

91
host/Connections.sys.mjs Normal file
View file

@ -0,0 +1,91 @@
// Actor-bound local inter-app channels. No caller-supplied identity or port owner.
const routes = {
search: ['system', 'search'],
'search-results': ['search', 'system'],
'app-metrics': ['search', 'system'],
mediacomms: ['music', 'system'],
};
export class Connections {
constructor(identity, notify) {
Object.assign(this, { identity, notify });
this.ports = new Map();
this.listeners = new Map();
}
subscribe(actor) {
this.listeners.set(actor, this.identity(actor).id);
for (const port of this.ports.values()) this.attach(port);
}
attach(port) {
if (port.receiver || !this.ports.has(port.id)) return;
const target = [...this.listeners.keys()].find(
(actor) =>
this.identity(actor)?.id === port.target &&
new URL(actor.manager.documentURI.spec).pathname === port.path,
);
if (!target) return;
port.receiver = target;
this.notify(target, 'connection', { keyword: port.keyword, id: port.id, side: 'receiver' });
for (const data of port.pending) this.notify(target, 'portmessage', { id: port.id, data });
port.pending = [];
}
connect(actor, keyword, apps) {
const route = routes[keyword],
app = this.identity(actor);
if (
!route ||
route[0] !== app.id ||
!apps.find((a) => a.id === route[1])?.manifest.connections?.[keyword]
)
throw new Error('CONNECTION_DENIED');
if ([...this.ports.values()].filter((p) => p.sender === actor).length >= 32)
throw new Error('QUOTA_EXCEEDED');
const receiver = apps.find((a) => a.id === route[1]);
const path = new URL(
receiver.manifest.connections[keyword].handler_path || '/index.html',
receiver.origin + '/',
).pathname;
const port = {
id: Services.uuid.generateUUID().toString(),
keyword,
sender: actor,
target: route[1],
path,
pending: [],
};
this.ports.set(port.id, port);
this.attach(port);
return [{ id: port.id, side: 'sender' }];
}
send(actor, { id, data }) {
const port = this.ports.get(id);
if (!port || (actor !== port.sender && actor !== port.receiver))
throw new Error('CONNECTION_DENIED');
if ((JSON.stringify(data)?.length || 0) > 1024 * 1024) throw new Error('VALUE_TOO_LARGE');
const target = actor === port.sender ? port.receiver : port.sender;
if (target) this.notify(target, 'portmessage', { id, data });
else {
if (port.pending.length >= 128) throw new Error('QUOTA_EXCEEDED');
port.pending.push(data);
}
return null;
}
close(actor, id) {
const port = this.ports.get(id);
if (!port || (actor !== port.sender && actor !== port.receiver))
throw new Error('CONNECTION_DENIED');
this.ports.delete(id);
for (const target of [port.sender, port.receiver])
if (target && target !== actor) {
try {
this.notify(target, 'portclose', { id });
} catch (_) {
/* Peer already destroyed. */
}
}
}
cleanup(actor) {
this.listeners.delete(actor);
for (const port of this.ports.values())
if (port.sender === actor || port.receiver === actor) this.close(actor, port.id);
}
}