drop-free.openapps.xyz

Source

This app’s code and revision history are public. Download a copy or explore the files below.

Public
The app’s code and revision history are public.
Owned app · rev b2e053fd98cb
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone 80ddb8c5df822e290afdd3c7
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
← All files
src/sw.js
// Drop's service worker. It keeps the app's own files so an installed Drop opens quickly, and
// receives files shared to Drop from another app (the share sheet on Android), handing them to
// the page that opens. The build (vite.config.ts) fills in the version and the list of app files.
const CACHE = "drop-shell-__VERSION__";
const SHELL = __SHELL__;

self.addEventListener("install", (e) => {
  e.waitUntil(caches.open(CACHE).then((c) => c.addAll(SHELL)).then(() => self.skipWaiting()));
});

self.addEventListener("activate", (e) => {
  e.waitUntil(
    caches.keys()
      .then((keys) => Promise.all(keys.filter((k) => k.startsWith("drop-shell-") && k !== CACHE).map((k) => caches.delete(k))))
      .then(() => self.clients.claim()),
  );
});

// Files shared to Drop wait here (in memory, never uploaded) until the sending screen asks for them.
let shared = null;
let sharedTaken = null;

self.addEventListener("fetch", (e) => {
  const req = e.request;
  const url = new URL(req.url);
  if (req.method === "POST" && url.pathname === "/share-target") {
    e.respondWith((async () => {
      const data = await req.formData().catch(() => null);
      shared = data ? data.getAll("files").filter((f) => typeof f !== "string") : [];
      return Response.redirect("/send?shared=1", 303);
    })());
    // Stay awake until the page has taken the files, or for a minute.
    e.waitUntil(new Promise((resolve) => { sharedTaken = resolve; setTimeout(resolve, 60000); }));
    return;
  }
  if (req.method !== "GET" || url.origin !== location.origin || url.pathname.startsWith("/__bounded/")) return;
  if (req.mode === "navigate") {
    // Every page is the same app shell: fresh when online, the saved copy when not.
    e.respondWith(fetch(req).catch(() => caches.match("/", { cacheName: CACHE })));
    return;
  }
  e.respondWith(caches.match(req, { cacheName: CACHE }).then((hit) => hit || fetch(req)));
});

self.addEventListener("message", (e) => {
  if (e.data !== "drop:shared?" || !e.source) return;
  e.source.postMessage({ t: "drop:shared", files: shared || [] });
  shared = null;
  sharedTaken?.();
});

Change history

Point OpenApps links to openapps.free
b2e053fd98 · 17 hours ago
Bind agent address in policy
ca424dd814 · 19 hours ago
Retry release capture
ae07f1a3fd · 19 hours ago
Use OpenApps service URLs and add contribution strip
0452ce136f · 19 hours ago
Bounded source sync
ca1bc00aa4 · 1 day ago
Bounded source sync
d4982911a0 · 1 day ago
Bounded source sync
18c97fe4ca · 1 day ago