wasm-host-sw.mjs raw
1 // sw-build: 20260611-v0.6.38
2 import * as sw from '../$runtime/sw.mjs';
3 import * as idb from '../$runtime/idb.mjs';
4 import { makeCoreHelpers, makeCommonBridge } from '../bridge-common.mjs';
5
6 let mem;
7 let xp;
8 const enc = new TextEncoder();
9 const dec = new TextDecoder();
10
11 // Spawn-channel state. Every moxie wasm module imports bridge.channel_send /
12 // channel_recv / channel_close (the spawn-channel ABI), so the import object
13 // must provide them or instantiation dies with "import object field
14 // 'channel_close' is not a Function". The other workers get these from
15 // makeCommonBridge; this host predated it and had none.
16 const _sabTable = new Map();
17 const _sabSeqRef = { value: 0 };
18 const _wasmUrlRef = { value: null };
19 const _buildHashRef = { value: null };
20 const _spawnedWorkerChans = new Map();
21
22 function readStr(ptr, len) {
23 if (len <= 0) return '';
24 return dec.decode(new Uint8Array(mem.buffer, ptr, len));
25 }
26
27 function writeStr(s) {
28 const bytes = enc.encode('' + s);
29 const ptr = xp.__alloc(bytes.length);
30 new Uint8Array(mem.buffer, ptr, bytes.length).set(bytes);
31 return [ptr, bytes.length];
32 }
33
34 function writeStrOut(s, rPtrAddr, rLenAddr) {
35 const [ptr, len] = writeStr(s);
36 const dv = new DataView(mem.buffer);
37 dv.setInt32(rPtrAddr, ptr, true);
38 dv.setInt32(rLenAddr, len, true);
39 }
40
41 function cb0(id) { xp.__cb0(id); }
42 function cbs(id, s) { const [ptr, len] = writeStr(s); xp.__cbs(id, ptr, len); }
43 function cbb(id, v) { xp.__cbb(id, v ? 1 : 0); }
44 function cbi(id, v) { xp.__cbi(id, v); }
45 function cbii(id, a, b) { xp.__cbii(id, a, b); }
46
47 function readNullSep(ptr, len) {
48 if (len <= 0) return [];
49 return readStr(ptr, len).split('\0');
50 }
51
52 const bridge = {
53 // --- sw lifecycle ---
54 sw_on_install(cbID) { sw.OnInstall(function(id) { cbi(cbID, id); }); },
55 sw_on_activate(cbID) { sw.OnActivate(function(id) { cbi(cbID, id); }); },
56 sw_on_fetch(cbID) { sw.OnFetch(function(id) { cbi(cbID, id); }); },
57 sw_on_message(cbID) { sw.OnMessage(function(id) { cbi(cbID, id); }); },
58
59 // --- event methods ---
60 sw_wait_until(event, cbID) {
61 sw.WaitUntil(event, function(done) { cb0(cbID); done(); });
62 },
63 sw_respond_with_cache_first(event) { sw.RespondWithCacheFirst(event); },
64 sw_respond_with_network_first(event) { sw.RespondWithNetworkFirst(event); },
65 sw_get_request_url(event, rPtrAddr, rLenAddr) {
66 writeStrOut(sw.GetRequestURL(event), rPtrAddr, rLenAddr);
67 },
68 sw_get_request_path(event, rPtrAddr, rLenAddr) {
69 writeStrOut(sw.GetRequestPath(event), rPtrAddr, rLenAddr);
70 },
71 sw_get_message_data(event, rPtrAddr, rLenAddr) {
72 writeStrOut(sw.GetMessageData(event), rPtrAddr, rLenAddr);
73 },
74 sw_get_message_client_id(event, rPtrAddr, rLenAddr) {
75 writeStrOut(sw.GetMessageClientID(event), rPtrAddr, rLenAddr);
76 },
77
78 // --- sw globals ---
79 sw_skip_waiting() { sw.SkipWaiting(); },
80 sw_claim_clients(cbID) { sw.ClaimClients(function() { cb0(cbID); }); },
81 sw_match_clients(cbID) { sw.MatchClients(function(c) { cbi(cbID, c); }); },
82 sw_post_message(client, ptr, len, cap) { sw.PostMessage(client, readStr(ptr, len)); },
83 sw_post_message_json(client, ptr, len, cap) { sw.PostMessageJSON(client, readStr(ptr, len)); },
84 sw_get_client_by_id(ptr, len, cap, cbID) {
85 sw.GetClientByID(readStr(ptr, len), function(c, found) { cbii(cbID, c, found ? 1 : 0); });
86 },
87 sw_origin(rPtrAddr, rLenAddr) { writeStrOut(sw.Origin(), rPtrAddr, rLenAddr); },
88 sw_log(ptr, len, cap) { sw.Log(readStr(ptr, len)); },
89
90 // --- cache ---
91 sw_cache_open(ptr, len, cap, cbID) {
92 sw.CacheOpen(readStr(ptr, len), function(c) { cbi(cbID, c); });
93 },
94 sw_cache_from_manifests(cache, filesPtr, filesLen, filesCap, count, cbID) {
95 sw.CacheFromManifests(cache, readNullSep(filesPtr, filesLen), function() { cb0(cbID); });
96 },
97 sw_cache_delete(ptr, len, cap, cbID) {
98 sw.CacheDelete(readStr(ptr, len), function() { cb0(cbID); });
99 },
100
101 // --- fetch ---
102 sw_fetch(ptr, len, cap, cbID) {
103 sw.Fetch(readStr(ptr, len), function(resp, ok) { cbii(cbID, resp, ok ? 1 : 0); });
104 },
105
106 // --- sse ---
107 sw_sse_connect(ptr, len, cap, cbID) {
108 return sw.SSEConnect(readStr(ptr, len), function(data) { cbs(cbID, data); });
109 },
110
111 // --- timers ---
112 sw_set_timeout(ms, cbID) { return sw.SetTimeout(ms, function() { cb0(cbID); }); },
113 sw_clear_timeout(t) { sw.ClearTimeout(t); },
114 sw_now_seconds() { return sw.NowSeconds(); },
115
116 // --- idb ---
117 idb_set_enc_key(ptr, len, cap) { idb.SetEncKey(readStr(ptr, len)); },
118 idb_open(cbID) { idb.Open(function() { cb0(cbID); }); },
119 idb_save_event(ptr, len, cap, cbID) {
120 idb.SaveEvent(readStr(ptr, len), function(ok) { cbb(cbID, ok); });
121 },
122 idb_query_events(ptr, len, cap, cbID) {
123 idb.QueryEvents(readStr(ptr, len), function(json) { cbs(cbID, json); });
124 },
125 idb_save_dm(ptr, len, cap, cbID) {
126 idb.SaveDM(readStr(ptr, len), function(status) { cbs(cbID, status); });
127 },
128 idb_query_dms(peerPtr, peerLen, peerCap, limit, until, cbID) {
129 idb.QueryDMs(readStr(peerPtr, peerLen), limit, Number(until), function(json) { cbs(cbID, json); });
130 },
131 idb_get_conversation_list(cbID) {
132 idb.GetConversationList(function(json) { cbs(cbID, json); });
133 },
134 idb_clear_dms_by_peer(ptr, len, cap, cbID) {
135 idb.ClearDMsByPeer(readStr(ptr, len), function() { cb0(cbID); });
136 },
137
138 // --- common (channel ops, spawn, subtle_random_bytes) ---
139 ...makeCommonBridge(
140 makeCoreHelpers(() => mem, () => xp),
141 _sabTable, _sabSeqRef, _wasmUrlRef, _buildHashRef, _spawnedWorkerChans,
142 ),
143 };
144
145 const wasi = {
146 fd_write(fd, iovs, iovs_len, nwritten_ptr) {
147 const dv = new DataView(mem.buffer);
148 let total = 0;
149 for (let i = 0; i < iovs_len; i++) {
150 const ptr = dv.getUint32(iovs + i * 8, true);
151 const len = dv.getUint32(iovs + i * 8 + 4, true);
152 const s = dec.decode(new Uint8Array(mem.buffer, ptr, len));
153 if (fd === 1) console.log(s);
154 else if (fd === 2) console.error(s);
155 total += len;
156 }
157 dv.setUint32(nwritten_ptr, total, true);
158 return 0;
159 },
160 clock_time_get(clock_id, precision, time_ptr) {
161 const dv = new DataView(mem.buffer);
162 const ms = (clock_id === 1) ? performance.now() : Date.now();
163 const ns = BigInt(Math.trunc(ms * 1e6));
164 dv.setBigUint64(time_ptr >>> 0, ns, true);
165 return 0;
166 },
167 };
168
169
170
171 async function boot() {
172 const { instance } = await WebAssembly.instantiateStreaming(
173 fetch('/$sw/sw.wasm'),
174 { bridge, wasi_snapshot_preview1: wasi }
175 );
176 mem = instance.exports.memory;
177 xp = instance.exports;
178 instance.exports._start();
179 }
180
181 boot().catch(e => console.error('SW WASM boot failed:', e));
182