@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.
- package/dist/cli/polly.js +75 -220
- package/dist/cli/polly.js.map +5 -4
- package/dist/cli/template-utils.js +81 -0
- package/dist/cli/template-utils.js.map +10 -0
- package/dist/vendor/verify/specs/Dockerfile +13 -0
- package/dist/vendor/verify/specs/README.md +37 -0
- package/dist/vendor/verify/specs/docker-compose.yml +9 -0
- package/dist/vendor/verify/specs/tla/MessageRouter.cfg +24 -0
- package/dist/vendor/verify/specs/tla/MessageRouter.tla +221 -0
- package/dist/vendor/verify/specs/tla/README.md +179 -0
- package/dist/vendor/verify/specs/verification.config.ts +61 -0
- package/dist/vendor/verify/src/cli.js +22 -19
- package/dist/vendor/verify/src/cli.js.map +5 -5
- package/dist/vendor/visualize/src/cli.js +379 -61
- package/dist/vendor/visualize/src/cli.js.map +11 -10
- package/package.json +2 -2
- package/templates/pwa/.gitignore.template +4 -0
- package/templates/pwa/README.md.template +144 -0
- package/templates/pwa/build.ts.template +56 -0
- package/templates/pwa/index.html.template +127 -0
- package/templates/pwa/package.json.template +19 -0
- package/templates/pwa/public/manifest.json.template +21 -0
- package/templates/pwa/server.ts.template +58 -0
- package/templates/pwa/src/main.ts.template +133 -0
- package/templates/pwa/src/service-worker.ts.template +161 -0
- package/templates/pwa/src/shared-worker.ts.template +135 -0
- package/templates/pwa/tsconfig.json.template +18 -0
|
@@ -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
|
+
}
|