@fairfox/polly 0.5.2 → 0.6.0

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.
Files changed (48) hide show
  1. package/dist/cli/polly.js +9 -9
  2. package/dist/cli/polly.js.map +4 -4
  3. package/dist/cli/template-utils.js +3 -3
  4. package/dist/cli/template-utils.js.map +3 -3
  5. package/dist/src/shared/state/app-state.d.ts +8 -0
  6. package/dist/vendor/verify/src/cli.js +78 -71
  7. package/dist/vendor/verify/src/cli.js.map +10 -10
  8. package/dist/vendor/verify/src/public-api.d.ts +41 -0
  9. package/dist/vendor/verify/src/public-api.js +26 -0
  10. package/dist/vendor/verify/src/public-api.js.map +10 -0
  11. package/dist/vendor/visualize/src/cli.js +108 -104
  12. package/dist/vendor/visualize/src/cli.js.map +13 -13
  13. package/package.json +15 -2
  14. package/templates/pwa/build.ts.template +37 -37
  15. package/templates/pwa/server.ts.template +53 -53
  16. package/templates/pwa/src/service-worker.ts.template +131 -135
  17. package/templates/pwa/src/shared-worker.ts.template +114 -109
  18. package/dist/shared/state/app-state.d.ts +0 -8
  19. /package/dist/{background → src/background}/api-client.d.ts +0 -0
  20. /package/dist/{background → src/background}/context-menu.d.ts +0 -0
  21. /package/dist/{background → src/background}/index.d.ts +0 -0
  22. /package/dist/{background → src/background}/log-store.d.ts +0 -0
  23. /package/dist/{background → src/background}/message-router.d.ts +0 -0
  24. /package/dist/{background → src/background}/offscreen-manager.d.ts +0 -0
  25. /package/dist/{index.d.ts → src/index.d.ts} +0 -0
  26. /package/dist/{shared → src/shared}/adapters/chrome/context-menus.chrome.d.ts +0 -0
  27. /package/dist/{shared → src/shared}/adapters/chrome/offscreen.chrome.d.ts +0 -0
  28. /package/dist/{shared → src/shared}/adapters/chrome/runtime.chrome.d.ts +0 -0
  29. /package/dist/{shared → src/shared}/adapters/chrome/storage.chrome.d.ts +0 -0
  30. /package/dist/{shared → src/shared}/adapters/chrome/tabs.chrome.d.ts +0 -0
  31. /package/dist/{shared → src/shared}/adapters/chrome/window.chrome.d.ts +0 -0
  32. /package/dist/{shared → src/shared}/adapters/context-menus.adapter.d.ts +0 -0
  33. /package/dist/{shared → src/shared}/adapters/fetch.adapter.d.ts +0 -0
  34. /package/dist/{shared → src/shared}/adapters/index.d.ts +0 -0
  35. /package/dist/{shared → src/shared}/adapters/logger.adapter.d.ts +0 -0
  36. /package/dist/{shared → src/shared}/adapters/offscreen.adapter.d.ts +0 -0
  37. /package/dist/{shared → src/shared}/adapters/runtime.adapter.d.ts +0 -0
  38. /package/dist/{shared → src/shared}/adapters/storage.adapter.d.ts +0 -0
  39. /package/dist/{shared → src/shared}/adapters/tabs.adapter.d.ts +0 -0
  40. /package/dist/{shared → src/shared}/adapters/window.adapter.d.ts +0 -0
  41. /package/dist/{shared → src/shared}/lib/context-helpers.d.ts +0 -0
  42. /package/dist/{shared → src/shared}/lib/context-specific-helpers.d.ts +0 -0
  43. /package/dist/{shared → src/shared}/lib/errors.d.ts +0 -0
  44. /package/dist/{shared → src/shared}/lib/handler-execution-tracker.d.ts +0 -0
  45. /package/dist/{shared → src/shared}/lib/message-bus.d.ts +0 -0
  46. /package/dist/{shared → src/shared}/lib/state.d.ts +0 -0
  47. /package/dist/{shared → src/shared}/lib/test-helpers.d.ts +0 -0
  48. /package/dist/{shared → src/shared}/types/messages.d.ts +0 -0
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@fairfox/polly",
3
- "version": "0.5.2",
3
+ "version": "0.6.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Multi-execution-context framework with reactive state and cross-context messaging for Chrome extensions, PWAs, and worker-based applications",
7
+ "workspaces": ["tests"],
7
8
  "main": "dist/index.js",
8
9
  "module": "dist/index.js",
9
10
  "types": "dist/index.d.ts",
@@ -42,6 +43,10 @@
42
43
  "./types": {
43
44
  "import": "./dist/src/shared/types/messages.js",
44
45
  "types": "./dist/shared/types/messages.d.ts"
46
+ },
47
+ "./verify": {
48
+ "import": "./dist/vendor/verify/src/public-api.js",
49
+ "types": "./dist/vendor/verify/src/public-api.d.ts"
45
50
  }
46
51
  },
47
52
  "files": ["dist", "templates", "README.md", "LICENSE"],
@@ -52,10 +57,18 @@
52
57
  "build:lib": "bun run build-lib.ts",
53
58
  "build:full-featured": "bun run scripts/build-user-extension.ts examples/full-featured",
54
59
  "build:full-featured:prod": "bun run scripts/build-user-extension.ts examples/full-featured --prod",
55
- "typecheck": "bunx tsc --noEmit",
60
+ "typecheck": "bunx tsc --noEmit && bun run --cwd tests typecheck",
61
+ "typecheck:tests": "bun run --cwd tests typecheck",
56
62
  "lint": "biome check .",
57
63
  "lint:fix": "biome check --write .",
58
64
  "format": "biome format --write .",
65
+ "test": "bun run --cwd tests test",
66
+ "test:watch": "bun run --cwd tests test:watch",
67
+ "test:framework": "bun run --cwd tests test:framework",
68
+ "test:framework:ui": "bun run --cwd tests test:framework:ui",
69
+ "test:framework:debug": "bun run --cwd tests test:framework:debug",
70
+ "test:framework:headed": "bun run --cwd tests test:framework:headed",
71
+ "test:all": "bun run --cwd tests test:all",
59
72
  "prepublishOnly": "bun run typecheck && bun run lint && bun run build:lib",
60
73
  "publish:public": "npm publish --access public"
61
74
  },
@@ -3,54 +3,54 @@
3
3
  * Uses Bun's built-in bundler
4
4
  */
5
5
 
6
- import { rmSync, cpSync, mkdirSync } from 'node:fs'
7
- import { join } from 'node:path'
6
+ import { cpSync, mkdirSync, rmSync } from "node:fs";
7
+ import { join } from "node:path";
8
8
 
9
- const distDir = './dist'
9
+ const distDir = "./dist";
10
10
 
11
11
  // Clean dist directory
12
- console.log('🧹 Cleaning dist directory...')
13
- rmSync(distDir, { recursive: true, force: true })
14
- mkdirSync(distDir, { recursive: true })
12
+ console.log("🧹 Cleaning dist directory...");
13
+ rmSync(distDir, { recursive: true, force: true });
14
+ mkdirSync(distDir, { recursive: true });
15
15
 
16
16
  // Copy static files
17
- console.log('📋 Copying static files...')
18
- cpSync('./public', distDir, { recursive: true, force: true })
19
- cpSync('./index.html', join(distDir, 'index.html'))
17
+ console.log("📋 Copying static files...");
18
+ cpSync("./public", distDir, { recursive: true, force: true });
19
+ cpSync("./index.html", join(distDir, "index.html"));
20
20
 
21
21
  // Build main application
22
- console.log('📦 Building main application...')
22
+ console.log("📦 Building main application...");
23
23
  await Bun.build({
24
- entrypoints: ['./src/main.ts'],
25
- outdir: join(distDir, 'src'),
26
- format: 'esm',
27
- minify: true,
28
- sourcemap: 'external',
29
- target: 'browser',
30
- })
24
+ entrypoints: ["./src/main.ts"],
25
+ outdir: join(distDir, "src"),
26
+ format: "esm",
27
+ minify: true,
28
+ sourcemap: "external",
29
+ target: "browser",
30
+ });
31
31
 
32
32
  // Build service worker
33
- console.log('⚙️ Building service worker...')
33
+ console.log("⚙️ Building service worker...");
34
34
  await Bun.build({
35
- entrypoints: ['./src/service-worker.ts'],
36
- outdir: join(distDir, 'src'),
37
- format: 'esm',
38
- minify: true,
39
- sourcemap: 'external',
40
- target: 'browser',
41
- })
35
+ entrypoints: ["./src/service-worker.ts"],
36
+ outdir: join(distDir, "src"),
37
+ format: "esm",
38
+ minify: true,
39
+ sourcemap: "external",
40
+ target: "browser",
41
+ });
42
42
 
43
43
  // Build shared worker
44
- console.log('👥 Building shared worker...')
44
+ console.log("👥 Building shared worker...");
45
45
  await Bun.build({
46
- entrypoints: ['./src/shared-worker.ts'],
47
- outdir: join(distDir, 'src'),
48
- format: 'esm',
49
- minify: true,
50
- sourcemap: 'external',
51
- target: 'browser',
52
- })
53
-
54
- console.log('✅ Build complete!')
55
- console.log(`\n📦 Output: ${distDir}/`)
56
- console.log('\n💡 To serve: bun run serve')
46
+ entrypoints: ["./src/shared-worker.ts"],
47
+ outdir: join(distDir, "src"),
48
+ format: "esm",
49
+ minify: true,
50
+ sourcemap: "external",
51
+ target: "browser",
52
+ });
53
+
54
+ console.log("✅ Build complete!");
55
+ console.log(`\n📦 Output: ${distDir}/`);
56
+ console.log("\n💡 To serve: bun run serve");
@@ -3,56 +3,56 @@
3
3
  * Serves the application with hot reload support
4
4
  */
5
5
 
6
- const port = 3000
7
-
8
- const server = Bun.serve({
9
- port,
10
- async fetch(req) {
11
- const url = new URL(req.url)
12
- let filePath = url.pathname
13
-
14
- // Serve root
15
- if (filePath === '/') {
16
- filePath = '/index.html'
17
- }
18
-
19
- // Try to serve from public directory first
20
- const publicFile = Bun.file(`./public${filePath}`)
21
- if (await publicFile.exists()) {
22
- return new Response(publicFile)
23
- }
24
-
25
- // Try to serve from root
26
- const rootFile = Bun.file(`.${filePath}`)
27
- if (await rootFile.exists()) {
28
- return new Response(rootFile)
29
- }
30
-
31
- // Handle TypeScript files - transpile on the fly
32
- if (filePath.endsWith('.ts')) {
33
- const tsFile = Bun.file(`.${filePath}`)
34
- if (await tsFile.exists()) {
35
- const transpiled = await Bun.build({
36
- entrypoints: [`.${filePath}`],
37
- format: 'esm',
38
- target: 'browser',
39
- })
40
-
41
- if (transpiled.outputs.length > 0) {
42
- return new Response(transpiled.outputs[0], {
43
- headers: {
44
- 'Content-Type': 'application/javascript',
45
- },
46
- })
47
- }
48
- }
49
- }
50
-
51
- // 404
52
- return new Response('Not Found', { status: 404 })
53
- },
54
- })
55
-
56
- console.log(`🚀 Server running at http://localhost:${port}`)
57
- console.log(`\n📱 PWA: {{PROJECT_NAME}}`)
58
- console.log(`\n💡 Open in browser and check the console for worker messages`)
6
+ const port = 3000;
7
+
8
+ Bun.serve({
9
+ port,
10
+ async fetch(req) {
11
+ const url = new URL(req.url);
12
+ let filePath = url.pathname;
13
+
14
+ // Serve root
15
+ if (filePath === "/") {
16
+ filePath = "/index.html";
17
+ }
18
+
19
+ // Try to serve from public directory first
20
+ const publicFile = Bun.file(`./public${filePath}`);
21
+ if (await publicFile.exists()) {
22
+ return new Response(publicFile);
23
+ }
24
+
25
+ // Try to serve from root
26
+ const rootFile = Bun.file(`.${filePath}`);
27
+ if (await rootFile.exists()) {
28
+ return new Response(rootFile);
29
+ }
30
+
31
+ // Handle TypeScript files - transpile on the fly
32
+ if (filePath.endsWith(".ts")) {
33
+ const tsFile = Bun.file(`.${filePath}`);
34
+ if (await tsFile.exists()) {
35
+ const transpiled = await Bun.build({
36
+ entrypoints: [`.${filePath}`],
37
+ format: "esm",
38
+ target: "browser",
39
+ });
40
+
41
+ if (transpiled.outputs.length > 0) {
42
+ return new Response(transpiled.outputs[0], {
43
+ headers: {
44
+ "Content-Type": "application/javascript",
45
+ },
46
+ });
47
+ }
48
+ }
49
+ }
50
+
51
+ // 404
52
+ return new Response("Not Found", { status: 404 });
53
+ },
54
+ });
55
+
56
+ console.log(`🚀 Server running at http://localhost:${port}`);
57
+ console.log(`\n📱 PWA: {{PROJECT_NAME}}`);
58
+ console.log("\n💡 Open in browser and check the console for worker messages");
@@ -4,158 +4,154 @@
4
4
  */
5
5
 
6
6
  /// <reference lib="WebWorker" />
7
- declare const self: ServiceWorkerGlobalScope
7
+ declare const self: ServiceWorkerGlobalScope;
8
8
 
9
- console.log('[SW] Service Worker loading...')
9
+ console.log("[SW] Service Worker loading...");
10
10
 
11
11
  // Cache configuration
12
- const CACHE_NAME = '{{PROJECT_NAME}}-v1'
13
- const urlsToCache = [
14
- '/',
15
- '/index.html',
16
- '/src/main.ts'
17
- ]
12
+ const CACHE_NAME = "{{PROJECT_NAME}}-v1";
13
+ const urlsToCache = ["/", "/index.html", "/src/main.ts"];
18
14
 
19
15
  // Install event - cache resources
20
- self.addEventListener('install', (event) => {
21
- console.log('[SW] Installing...')
16
+ self.addEventListener("install", (event) => {
17
+ console.log("[SW] Installing...");
22
18
 
23
- event.waitUntil(
24
- caches.open(CACHE_NAME).then((cache) => {
25
- console.log('[SW] Caching resources')
26
- return cache.addAll(urlsToCache)
27
- })
28
- )
19
+ event.waitUntil(
20
+ caches.open(CACHE_NAME).then((cache) => {
21
+ console.log("[SW] Caching resources");
22
+ return cache.addAll(urlsToCache);
23
+ }),
24
+ );
29
25
 
30
- // Activate immediately
31
- self.skipWaiting()
32
- })
26
+ // Activate immediately
27
+ void self.skipWaiting();
28
+ });
33
29
 
34
30
  // Activate event - clean up old caches
35
- self.addEventListener('activate', (event) => {
36
- console.log('[SW] Activating...')
37
-
38
- event.waitUntil(
39
- caches.keys().then((cacheNames) => {
40
- return Promise.all(
41
- cacheNames
42
- .filter((name) => name !== CACHE_NAME)
43
- .map((name) => caches.delete(name))
44
- )
45
- })
46
- )
47
-
48
- // Take control immediately
49
- return self.clients.claim()
50
- })
31
+ self.addEventListener("activate", (event) => {
32
+ console.log("[SW] Activating...");
33
+
34
+ event.waitUntil(
35
+ caches.keys().then((cacheNames) => {
36
+ return Promise.all(
37
+ cacheNames
38
+ .filter((name) => name !== CACHE_NAME)
39
+ .map((name) => caches.delete(name)),
40
+ );
41
+ }),
42
+ );
43
+
44
+ // Take control immediately
45
+ void self.clients.claim();
46
+ });
51
47
 
52
48
  // Fetch event - serve from cache, fallback to network
53
- self.addEventListener('fetch', (event) => {
54
- event.respondWith(
55
- caches.match(event.request).then((response) => {
56
- // Cache hit - return response
57
- if (response) {
58
- return response
59
- }
60
-
61
- // Clone the request
62
- const fetchRequest = event.request.clone()
63
-
64
- return fetch(fetchRequest).then((response) => {
65
- // Check if valid response
66
- if (!response || response.status !== 200 || response.type !== 'basic') {
67
- return response
68
- }
69
-
70
- // Clone the response
71
- const responseToCache = response.clone()
72
-
73
- caches.open(CACHE_NAME).then((cache) => {
74
- cache.put(event.request, responseToCache)
75
- })
76
-
77
- return response
78
- })
79
- })
80
- )
81
- })
49
+ self.addEventListener("fetch", (event) => {
50
+ event.respondWith(
51
+ caches.match(event.request).then((response) => {
52
+ // Cache hit - return response
53
+ if (response) {
54
+ return response;
55
+ }
56
+
57
+ // Clone the request
58
+ const fetchRequest = event.request.clone();
59
+
60
+ return fetch(fetchRequest).then((response) => {
61
+ // Check if valid response
62
+ if (
63
+ !response ||
64
+ response.status !== 200 ||
65
+ response.type !== "basic"
66
+ ) {
67
+ return response;
68
+ }
69
+
70
+ // Clone the response
71
+ const responseToCache = response.clone();
72
+
73
+ void caches.open(CACHE_NAME).then((cache) => {
74
+ void cache.put(event.request, responseToCache);
75
+ });
76
+
77
+ return response;
78
+ });
79
+ }),
80
+ );
81
+ });
82
82
 
83
83
  // Message handling
84
- self.addEventListener('message', (event) => {
85
- console.log('[SW] Received message:', event.data)
86
-
87
- switch (event.data.type) {
88
- case 'PING':
89
- // Respond to ping
90
- event.ports[0]?.postMessage({
91
- type: 'PONG',
92
- timestamp: Date.now(),
93
- originalTimestamp: event.data.timestamp
94
- })
95
-
96
- // Also broadcast to all clients
97
- self.clients.matchAll().then((clients) => {
98
- clients.forEach((client) => {
99
- client.postMessage({
100
- type: 'PONG',
101
- from: 'service-worker',
102
- timestamp: Date.now()
103
- })
104
- })
105
- })
106
- break
107
-
108
- case 'BROADCAST':
109
- // Broadcast to all clients
110
- self.clients.matchAll().then((clients) => {
111
- console.log(`[SW] Broadcasting to ${clients.length} clients`)
112
- clients.forEach((client) => {
113
- client.postMessage({
114
- type: 'BROADCAST',
115
- data: event.data.data,
116
- from: 'service-worker',
117
- timestamp: Date.now()
118
- })
119
- })
120
- })
121
- break
122
-
123
- case 'SKIP_WAITING':
124
- self.skipWaiting()
125
- break
126
-
127
- default:
128
- console.log('[SW] Unknown message type:', event.data.type)
129
- }
130
- })
84
+ self.addEventListener("message", (event) => {
85
+ console.log("[SW] Received message:", event.data);
86
+
87
+ switch (event.data.type) {
88
+ case "PING":
89
+ // Respond to ping
90
+ event.ports[0]?.postMessage({
91
+ type: "PONG",
92
+ timestamp: Date.now(),
93
+ originalTimestamp: event.data.timestamp,
94
+ });
95
+
96
+ // Also broadcast to all clients
97
+ void self.clients.matchAll().then((clients) => {
98
+ for (const client of clients) {
99
+ client.postMessage({
100
+ type: "PONG",
101
+ from: "service-worker",
102
+ timestamp: Date.now(),
103
+ });
104
+ }
105
+ });
106
+ break;
107
+
108
+ case "BROADCAST":
109
+ // Broadcast to all clients
110
+ void self.clients.matchAll().then((clients) => {
111
+ console.log(`[SW] Broadcasting to ${clients.length} clients`);
112
+ for (const client of clients) {
113
+ client.postMessage({
114
+ type: "BROADCAST",
115
+ data: event.data.data,
116
+ from: "service-worker",
117
+ timestamp: Date.now(),
118
+ });
119
+ }
120
+ });
121
+ break;
122
+
123
+ case "SKIP_WAITING":
124
+ void self.skipWaiting();
125
+ break;
126
+
127
+ default:
128
+ console.log("[SW] Unknown message type:", event.data.type);
129
+ }
130
+ });
131
131
 
132
132
  // Push notification event (example)
133
- self.addEventListener('push', (event) => {
134
- console.log('[SW] Push received')
135
-
136
- const data = event.data?.json() ?? {}
137
- const title = data.title || '{{PROJECT_NAME}}'
138
- const options = {
139
- body: data.body || 'New notification',
140
- icon: '/icon-192.png',
141
- badge: '/icon-192.png',
142
- data: data
143
- }
144
-
145
- event.waitUntil(
146
- self.registration.showNotification(title, options)
147
- )
148
- })
133
+ self.addEventListener("push", (event) => {
134
+ console.log("[SW] Push received");
135
+
136
+ const data = event.data?.json() ?? {};
137
+ const title = data.title || "{{PROJECT_NAME}}";
138
+ const options = {
139
+ body: data.body || "New notification",
140
+ icon: "/icon-192.png",
141
+ badge: "/icon-192.png",
142
+ data: data,
143
+ };
144
+
145
+ event.waitUntil(self.registration.showNotification(title, options));
146
+ });
149
147
 
150
148
  // Notification click event
151
- self.addEventListener('notificationclick', (event) => {
152
- console.log('[SW] Notification clicked')
149
+ self.addEventListener("notificationclick", (event) => {
150
+ console.log("[SW] Notification clicked");
153
151
 
154
- event.notification.close()
152
+ event.notification.close();
155
153
 
156
- event.waitUntil(
157
- self.clients.openWindow('/')
158
- )
159
- })
154
+ event.waitUntil(self.clients.openWindow("/"));
155
+ });
160
156
 
161
- console.log('[SW] Service Worker loaded')
157
+ console.log("[SW] Service Worker loaded");