@fairfox/polly 0.1.5 → 0.2.1

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,161 @@
1
+ /**
2
+ * Service Worker Context
3
+ * Handles background tasks, caching, and push notifications
4
+ */
5
+
6
+ /// <reference lib="WebWorker" />
7
+ declare const self: ServiceWorkerGlobalScope
8
+
9
+ console.log('[SW] Service Worker loading...')
10
+
11
+ // Cache configuration
12
+ const CACHE_NAME = '{{PROJECT_NAME}}-v1'
13
+ const urlsToCache = [
14
+ '/',
15
+ '/index.html',
16
+ '/src/main.ts'
17
+ ]
18
+
19
+ // Install event - cache resources
20
+ self.addEventListener('install', (event) => {
21
+ console.log('[SW] Installing...')
22
+
23
+ event.waitUntil(
24
+ caches.open(CACHE_NAME).then((cache) => {
25
+ console.log('[SW] Caching resources')
26
+ return cache.addAll(urlsToCache)
27
+ })
28
+ )
29
+
30
+ // Activate immediately
31
+ self.skipWaiting()
32
+ })
33
+
34
+ // 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
+ })
51
+
52
+ // 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
+ })
82
+
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
+ })
131
+
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
+ })
149
+
150
+ // Notification click event
151
+ self.addEventListener('notificationclick', (event) => {
152
+ console.log('[SW] Notification clicked')
153
+
154
+ event.notification.close()
155
+
156
+ event.waitUntil(
157
+ self.clients.openWindow('/')
158
+ )
159
+ })
160
+
161
+ console.log('[SW] Service Worker loaded')
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Shared Worker Context
3
+ * Shared state and coordination across multiple tabs/windows
4
+ */
5
+
6
+ /// <reference lib="WebWorker" />
7
+ declare const self: SharedWorkerGlobalScope
8
+
9
+ console.log('[Shared Worker] Starting...')
10
+
11
+ // Track connected ports (tabs/windows)
12
+ const ports: MessagePort[] = []
13
+ let messageCount = 0
14
+
15
+ // Shared state across all tabs
16
+ interface SharedState {
17
+ connectedTabs: number
18
+ totalMessages: number
19
+ lastActivity: number
20
+ }
21
+
22
+ const state: SharedState = {
23
+ connectedTabs: 0,
24
+ totalMessages: 0,
25
+ lastActivity: Date.now()
26
+ }
27
+
28
+ // Connection event - when a new tab connects
29
+ self.addEventListener('connect', (event) => {
30
+ const port = event.ports[0]
31
+ ports.push(port)
32
+ state.connectedTabs = ports.length
33
+
34
+ console.log(`[Shared Worker] New connection. Total ports: ${ports.length}`)
35
+
36
+ // Send welcome message
37
+ port.postMessage({
38
+ type: 'CONNECTED',
39
+ state: state,
40
+ timestamp: Date.now()
41
+ })
42
+
43
+ // Listen for messages from this port
44
+ port.addEventListener('message', (messageEvent) => {
45
+ handleMessage(messageEvent.data, port)
46
+ })
47
+
48
+ // Start listening
49
+ port.start()
50
+
51
+ // Notify all tabs about new connection
52
+ broadcast({
53
+ type: 'TAB_CONNECTED',
54
+ connectedTabs: state.connectedTabs
55
+ })
56
+ })
57
+
58
+ function handleMessage(data: any, sourcePort: MessagePort) {
59
+ console.log('[Shared Worker] Received:', data)
60
+
61
+ state.totalMessages++
62
+ state.lastActivity = Date.now()
63
+
64
+ switch (data.type) {
65
+ case 'PING':
66
+ // Respond to ping
67
+ sourcePort.postMessage({
68
+ type: 'PONG',
69
+ timestamp: Date.now(),
70
+ originalTimestamp: data.timestamp,
71
+ state: state
72
+ })
73
+ break
74
+
75
+ case 'BROADCAST':
76
+ // Broadcast to all connected tabs
77
+ broadcast({
78
+ type: 'BROADCAST',
79
+ data: data.data,
80
+ from: 'shared-worker',
81
+ timestamp: Date.now()
82
+ })
83
+ break
84
+
85
+ case 'GET_STATE':
86
+ // Send current state
87
+ sourcePort.postMessage({
88
+ type: 'STATE',
89
+ state: state,
90
+ timestamp: Date.now()
91
+ })
92
+ break
93
+
94
+ case 'INCREMENT_COUNTER':
95
+ // Example of shared state manipulation
96
+ messageCount++
97
+ broadcast({
98
+ type: 'COUNTER_UPDATED',
99
+ count: messageCount,
100
+ timestamp: Date.now()
101
+ })
102
+ break
103
+
104
+ default:
105
+ console.log('[Shared Worker] Unknown message type:', data.type)
106
+ sourcePort.postMessage({
107
+ type: 'ERROR',
108
+ message: `Unknown message type: ${data.type}`
109
+ })
110
+ }
111
+ }
112
+
113
+ // Broadcast message to all connected tabs
114
+ function broadcast(message: any) {
115
+ console.log(`[Shared Worker] Broadcasting to ${ports.length} ports:`, message)
116
+
117
+ ports.forEach((port) => {
118
+ try {
119
+ port.postMessage(message)
120
+ } catch (error) {
121
+ console.error('[Shared Worker] Failed to send message to port:', error)
122
+ }
123
+ })
124
+ }
125
+
126
+ // Periodic heartbeat to all tabs
127
+ setInterval(() => {
128
+ broadcast({
129
+ type: 'HEARTBEAT',
130
+ state: state,
131
+ timestamp: Date.now()
132
+ })
133
+ }, 30000) // Every 30 seconds
134
+
135
+ console.log('[Shared Worker] Ready')
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "lib": ["ES2022", "DOM", "DOM.Iterable", "WebWorker"],
6
+ "moduleResolution": "bundler",
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "resolveJsonModule": true,
12
+ "allowSyntheticDefaultImports": true,
13
+ "isolatedModules": true,
14
+ "noEmit": true
15
+ },
16
+ "include": ["src/**/*"],
17
+ "exclude": ["node_modules", "dist"]
18
+ }