wasm-host-sw.mjs raw

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