@tokenbuddy/tokenbuddy 1.0.15 → 1.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <meta name="theme-color" content="#07111f" />
7
+ <meta name="application-name" content="TokenBuddy" />
8
+ <meta name="apple-mobile-web-app-title" content="TokenBuddy" />
9
+ <meta name="apple-mobile-web-app-capable" content="yes" />
10
+ <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
11
+ <link rel="manifest" href="/manifest.webmanifest" />
12
+ <link rel="icon" type="image/png" sizes="192x192" href="/icons/tokenbuddy-192.png" />
13
+ <link rel="apple-touch-icon" href="/icons/apple-touch-icon.png" />
14
+ <title>TokenBuddy · Local Control</title>
15
+ <script type="module" crossorigin src="/assets/index-YHs-Ca0f.js"></script>
16
+ <link rel="stylesheet" crossorigin href="/assets/index-UMiTTeo8.css">
17
+ </head>
18
+ <body>
19
+ <div id="root"></div>
20
+ </body>
21
+ </html>
@@ -0,0 +1,28 @@
1
+ {
2
+ "id": "/",
3
+ "name": "TokenBuddy Local Control",
4
+ "short_name": "TokenBuddy",
5
+ "description": "Local TokenBuddy buyer control console.",
6
+ "start_url": "/overview",
7
+ "scope": "/",
8
+ "display": "standalone",
9
+ "display_override": ["window-controls-overlay", "standalone", "minimal-ui"],
10
+ "background_color": "#07111f",
11
+ "theme_color": "#07111f",
12
+ "orientation": "any",
13
+ "categories": ["developer", "productivity", "utilities"],
14
+ "icons": [
15
+ {
16
+ "src": "/icons/tokenbuddy-192.png",
17
+ "sizes": "192x192",
18
+ "type": "image/png",
19
+ "purpose": "any maskable"
20
+ },
21
+ {
22
+ "src": "/icons/tokenbuddy-512.png",
23
+ "sizes": "512x512",
24
+ "type": "image/png",
25
+ "purpose": "any maskable"
26
+ }
27
+ ]
28
+ }
@@ -0,0 +1,59 @@
1
+ const CACHE_NAME = "tokenbuddy-ui-v1";
2
+ const APP_SHELL = [
3
+ "/",
4
+ "/overview",
5
+ "/manifest.webmanifest",
6
+ "/icons/tokenbuddy-192.png",
7
+ "/icons/tokenbuddy-512.png",
8
+ "/icons/apple-touch-icon.png"
9
+ ];
10
+
11
+ self.addEventListener("install", (event) => {
12
+ event.waitUntil(
13
+ caches.open(CACHE_NAME).then((cache) => cache.addAll(APP_SHELL))
14
+ );
15
+ self.skipWaiting();
16
+ });
17
+
18
+ self.addEventListener("activate", (event) => {
19
+ event.waitUntil(
20
+ caches.keys().then((keys) =>
21
+ Promise.all(keys.filter((key) => key !== CACHE_NAME).map((key) => caches.delete(key)))
22
+ )
23
+ );
24
+ self.clients.claim();
25
+ });
26
+
27
+ self.addEventListener("fetch", (event) => {
28
+ const { request } = event;
29
+ if (request.method !== "GET") {
30
+ return;
31
+ }
32
+
33
+ const url = new URL(request.url);
34
+ if (url.origin !== self.location.origin) {
35
+ return;
36
+ }
37
+
38
+ if (request.mode === "navigate") {
39
+ event.respondWith(
40
+ fetch(request).catch(() => caches.match("/overview").then((response) => response || caches.match("/")))
41
+ );
42
+ return;
43
+ }
44
+
45
+ if (url.pathname.startsWith("/assets/") || url.pathname.startsWith("/icons/") || url.pathname === "/manifest.webmanifest") {
46
+ event.respondWith(
47
+ caches.match(request).then((cached) => {
48
+ if (cached) {
49
+ return cached;
50
+ }
51
+ return fetch(request).then((response) => {
52
+ const copy = response.clone();
53
+ caches.open(CACHE_NAME).then((cache) => cache.put(request, copy));
54
+ return response;
55
+ });
56
+ })
57
+ );
58
+ }
59
+ });
@@ -302,6 +302,36 @@ describe("TokenbuddyDaemon control-plane UI endpoints (PR-0)", () => {
302
302
  });
303
303
  });
304
304
 
305
+ // ─── Bundled PWA Static Assets ────────────────────────────────
306
+ describe("bundled tb-ui static assets", () => {
307
+ it("serves the installable PWA shell from the control plane", async () => {
308
+ const overviewRes = await fetch(controlUrl("/overview"));
309
+ expect(overviewRes.status).toBe(200);
310
+ expect(overviewRes.headers.get("content-type")).toContain("text/html");
311
+ expect(await overviewRes.text()).toContain("/manifest.webmanifest");
312
+
313
+ const manifestRes = await fetch(controlUrl("/manifest.webmanifest"));
314
+ expect(manifestRes.status).toBe(200);
315
+ expect(manifestRes.headers.get("content-type")).toContain("application/manifest+json");
316
+ const manifest = await manifestRes.json() as { start_url: string; icons: Array<{ src: string; sizes: string }> };
317
+ expect(manifest.start_url).toBe("/overview");
318
+ expect(manifest.icons).toEqual(expect.arrayContaining([
319
+ expect.objectContaining({ src: "/icons/tokenbuddy-192.png", sizes: "192x192" }),
320
+ expect.objectContaining({ src: "/icons/tokenbuddy-512.png", sizes: "512x512" })
321
+ ]));
322
+
323
+ const serviceWorkerRes = await fetch(controlUrl("/sw.js"));
324
+ expect(serviceWorkerRes.status).toBe(200);
325
+ expect(serviceWorkerRes.headers.get("content-type")).toContain("application/javascript");
326
+ expect(await serviceWorkerRes.text()).toContain("tokenbuddy-ui-v1");
327
+
328
+ const iconRes = await fetch(controlUrl("/icons/tokenbuddy-192.png"));
329
+ expect(iconRes.status).toBe(200);
330
+ expect(iconRes.headers.get("content-type")).toContain("image/png");
331
+ expect(Number(iconRes.headers.get("content-length"))).toBeGreaterThan(1_000);
332
+ });
333
+ });
334
+
305
335
  // ─── GET /providers/status ───────────────────────────────────
306
336
  describe("GET /providers/status", () => {
307
337
  it("returns read-only client tool status with a CLI install command", async () => {