@fairfox/polly 0.14.0 → 0.15.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.
- package/dist/src/background/index.js +342 -3
- package/dist/src/background/index.js.map +7 -4
- package/dist/src/background/message-router.js +342 -3
- package/dist/src/background/message-router.js.map +7 -4
- package/dist/src/index.js +402 -99
- package/dist/src/index.js.map +8 -5
- package/dist/src/shared/adapters/index.d.ts +3 -0
- package/dist/src/shared/adapters/index.js +356 -4
- package/dist/src/shared/adapters/index.js.map +7 -4
- package/dist/src/shared/lib/adapter-factory.d.ts +80 -0
- package/dist/src/shared/lib/context-helpers.js +342 -3
- package/dist/src/shared/lib/context-helpers.js.map +7 -4
- package/dist/src/shared/lib/message-bus.js +342 -3
- package/dist/src/shared/lib/message-bus.js.map +7 -4
- package/dist/src/shared/lib/state.d.ts +5 -1
- package/dist/src/shared/lib/state.js +274 -1173
- package/dist/src/shared/lib/state.js.map +6 -19
- package/dist/src/shared/lib/storage-adapter.d.ts +42 -0
- package/dist/src/shared/lib/sync-adapter.d.ts +79 -0
- package/dist/src/shared/state/app-state.js +294 -1173
- package/dist/src/shared/state/app-state.js.map +6 -18
- package/dist/tools/analysis/src/extract/handlers.d.ts +48 -1
- package/dist/tools/analysis/src/types/core.d.ts +20 -0
- package/dist/tools/teach/src/cli.js +454 -7
- package/dist/tools/teach/src/cli.js.map +4 -4
- package/dist/tools/teach/src/index.js +232 -7
- package/dist/tools/teach/src/index.js.map +3 -3
- package/dist/tools/verify/src/cli.js +234 -9
- package/dist/tools/verify/src/cli.js.map +4 -4
- package/dist/tools/visualize/src/cli.js +232 -7
- package/dist/tools/visualize/src/cli.js.map +3 -3
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -48,6 +48,293 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
48
48
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
+
// src/shared/lib/storage-adapter.ts
|
|
52
|
+
var exports_storage_adapter = {};
|
|
53
|
+
__export(exports_storage_adapter, {
|
|
54
|
+
createStorageAdapter: () => createStorageAdapter,
|
|
55
|
+
MemoryStorageAdapter: () => MemoryStorageAdapter,
|
|
56
|
+
IndexedDBAdapter: () => IndexedDBAdapter,
|
|
57
|
+
ChromeStorageAdapter: () => ChromeStorageAdapter2
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
class IndexedDBAdapter {
|
|
61
|
+
dbName;
|
|
62
|
+
storeName = "state";
|
|
63
|
+
dbPromise = null;
|
|
64
|
+
constructor(dbName = "polly-state") {
|
|
65
|
+
this.dbName = dbName;
|
|
66
|
+
}
|
|
67
|
+
getDB() {
|
|
68
|
+
if (this.dbPromise)
|
|
69
|
+
return this.dbPromise;
|
|
70
|
+
this.dbPromise = new Promise((resolve, reject) => {
|
|
71
|
+
const request = indexedDB.open(this.dbName, 1);
|
|
72
|
+
request.onerror = () => reject(request.error);
|
|
73
|
+
request.onsuccess = () => resolve(request.result);
|
|
74
|
+
request.onupgradeneeded = (event) => {
|
|
75
|
+
const db = event.target.result;
|
|
76
|
+
if (!db.objectStoreNames.contains(this.storeName)) {
|
|
77
|
+
db.createObjectStore(this.storeName);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
return this.dbPromise;
|
|
82
|
+
}
|
|
83
|
+
async get(keys) {
|
|
84
|
+
try {
|
|
85
|
+
const db = await this.getDB();
|
|
86
|
+
const result = {};
|
|
87
|
+
await Promise.all(keys.map((key) => new Promise((resolve, reject) => {
|
|
88
|
+
const transaction = db.transaction([this.storeName], "readonly");
|
|
89
|
+
const store = transaction.objectStore(this.storeName);
|
|
90
|
+
const request = store.get(key);
|
|
91
|
+
request.onerror = () => reject(request.error);
|
|
92
|
+
request.onsuccess = () => {
|
|
93
|
+
if (request.result !== undefined) {
|
|
94
|
+
result[key] = request.result;
|
|
95
|
+
}
|
|
96
|
+
resolve();
|
|
97
|
+
};
|
|
98
|
+
})));
|
|
99
|
+
return result;
|
|
100
|
+
} catch (error) {
|
|
101
|
+
console.warn("[Polly] IndexedDB get failed:", error);
|
|
102
|
+
return {};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async set(items) {
|
|
106
|
+
try {
|
|
107
|
+
const db = await this.getDB();
|
|
108
|
+
await Promise.all(Object.entries(items).map(([key, value]) => new Promise((resolve, reject) => {
|
|
109
|
+
const transaction = db.transaction([this.storeName], "readwrite");
|
|
110
|
+
const store = transaction.objectStore(this.storeName);
|
|
111
|
+
const request = store.put(value, key);
|
|
112
|
+
request.onerror = () => reject(request.error);
|
|
113
|
+
request.onsuccess = () => resolve();
|
|
114
|
+
})));
|
|
115
|
+
} catch (error) {
|
|
116
|
+
console.warn("[Polly] IndexedDB set failed:", error);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async remove(keys) {
|
|
120
|
+
try {
|
|
121
|
+
const db = await this.getDB();
|
|
122
|
+
await Promise.all(keys.map((key) => new Promise((resolve, reject) => {
|
|
123
|
+
const transaction = db.transaction([this.storeName], "readwrite");
|
|
124
|
+
const store = transaction.objectStore(this.storeName);
|
|
125
|
+
const request = store.delete(key);
|
|
126
|
+
request.onerror = () => reject(request.error);
|
|
127
|
+
request.onsuccess = () => resolve();
|
|
128
|
+
})));
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.warn("[Polly] IndexedDB remove failed:", error);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
class ChromeStorageAdapter2 {
|
|
136
|
+
async get(keys) {
|
|
137
|
+
if (typeof chrome === "undefined" || !chrome.storage) {
|
|
138
|
+
return {};
|
|
139
|
+
}
|
|
140
|
+
try {
|
|
141
|
+
return await chrome.storage.local.get(keys);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
console.warn("[Polly] Chrome storage get failed:", error);
|
|
144
|
+
return {};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async set(items) {
|
|
148
|
+
if (typeof chrome === "undefined" || !chrome.storage) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
try {
|
|
152
|
+
await chrome.storage.local.set(items);
|
|
153
|
+
} catch (error) {
|
|
154
|
+
console.warn("[Polly] Chrome storage set failed:", error);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
async remove(keys) {
|
|
158
|
+
if (typeof chrome === "undefined" || !chrome.storage) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
await chrome.storage.local.remove(keys);
|
|
163
|
+
} catch (error) {
|
|
164
|
+
console.warn("[Polly] Chrome storage remove failed:", error);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
class MemoryStorageAdapter {
|
|
170
|
+
storage = new Map;
|
|
171
|
+
async get(keys) {
|
|
172
|
+
const result = {};
|
|
173
|
+
for (const key of keys) {
|
|
174
|
+
const value = this.storage.get(key);
|
|
175
|
+
if (value !== undefined) {
|
|
176
|
+
result[key] = value;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
async set(items) {
|
|
182
|
+
for (const [key, value] of Object.entries(items)) {
|
|
183
|
+
this.storage.set(key, value);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
async remove(keys) {
|
|
187
|
+
for (const key of keys) {
|
|
188
|
+
this.storage.delete(key);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function createStorageAdapter() {
|
|
193
|
+
if (typeof chrome !== "undefined" && chrome.storage && chrome.runtime) {
|
|
194
|
+
return new ChromeStorageAdapter2;
|
|
195
|
+
}
|
|
196
|
+
if (typeof indexedDB !== "undefined") {
|
|
197
|
+
return new IndexedDBAdapter;
|
|
198
|
+
}
|
|
199
|
+
return new MemoryStorageAdapter;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// src/shared/lib/sync-adapter.ts
|
|
203
|
+
var exports_sync_adapter = {};
|
|
204
|
+
__export(exports_sync_adapter, {
|
|
205
|
+
createSyncAdapter: () => createSyncAdapter,
|
|
206
|
+
NoOpSyncAdapter: () => NoOpSyncAdapter,
|
|
207
|
+
ChromeRuntimeSyncAdapter: () => ChromeRuntimeSyncAdapter,
|
|
208
|
+
BroadcastChannelSyncAdapter: () => BroadcastChannelSyncAdapter
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
class NoOpSyncAdapter {
|
|
212
|
+
broadcast(_message) {}
|
|
213
|
+
onMessage(_callback) {
|
|
214
|
+
return () => {};
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
class ChromeRuntimeSyncAdapter {
|
|
219
|
+
listeners = [];
|
|
220
|
+
port = null;
|
|
221
|
+
constructor() {
|
|
222
|
+
if (typeof chrome !== "undefined" && chrome.runtime) {
|
|
223
|
+
chrome.runtime.onMessage.addListener((message, _sender, _sendResponse) => {
|
|
224
|
+
if (message.type === "STATE_SYNC") {
|
|
225
|
+
this.listeners.forEach((listener) => {
|
|
226
|
+
listener(message);
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
broadcast(message) {
|
|
233
|
+
if (typeof chrome === "undefined" || !chrome.runtime) {
|
|
234
|
+
console.warn("[SyncAdapter] chrome.runtime not available");
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
try {
|
|
238
|
+
chrome.runtime.sendMessage({
|
|
239
|
+
type: "STATE_SYNC",
|
|
240
|
+
key: message.key,
|
|
241
|
+
value: message.value,
|
|
242
|
+
clock: message.clock
|
|
243
|
+
});
|
|
244
|
+
} catch (error) {
|
|
245
|
+
console.warn("[SyncAdapter] Failed to broadcast state update:", error);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
onMessage(callback) {
|
|
249
|
+
this.listeners.push(callback);
|
|
250
|
+
return () => {
|
|
251
|
+
const index = this.listeners.indexOf(callback);
|
|
252
|
+
if (index > -1) {
|
|
253
|
+
this.listeners.splice(index, 1);
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
connect() {
|
|
258
|
+
return Promise.resolve();
|
|
259
|
+
}
|
|
260
|
+
disconnect() {
|
|
261
|
+
this.listeners = [];
|
|
262
|
+
if (this.port) {
|
|
263
|
+
this.port.disconnect();
|
|
264
|
+
this.port = null;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
isConnected() {
|
|
268
|
+
return typeof chrome !== "undefined" && !!chrome.runtime;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
class BroadcastChannelSyncAdapter {
|
|
273
|
+
channel = null;
|
|
274
|
+
listeners = [];
|
|
275
|
+
constructor(channelName = "polly-sync") {
|
|
276
|
+
if (typeof BroadcastChannel !== "undefined") {
|
|
277
|
+
this.channel = new BroadcastChannel(channelName);
|
|
278
|
+
this.channel.onmessage = (event) => {
|
|
279
|
+
if (event.data.type === "STATE_SYNC") {
|
|
280
|
+
this.listeners.forEach((listener) => {
|
|
281
|
+
listener(event.data);
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
} else {
|
|
286
|
+
console.warn("[SyncAdapter] BroadcastChannel not available");
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
broadcast(message) {
|
|
290
|
+
if (!this.channel) {
|
|
291
|
+
console.warn("[SyncAdapter] BroadcastChannel not initialized");
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
try {
|
|
295
|
+
this.channel.postMessage({
|
|
296
|
+
type: "STATE_SYNC",
|
|
297
|
+
key: message.key,
|
|
298
|
+
value: message.value,
|
|
299
|
+
clock: message.clock
|
|
300
|
+
});
|
|
301
|
+
} catch (error) {
|
|
302
|
+
console.warn("[SyncAdapter] Failed to broadcast state update:", error);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
onMessage(callback) {
|
|
306
|
+
this.listeners.push(callback);
|
|
307
|
+
return () => {
|
|
308
|
+
const index = this.listeners.indexOf(callback);
|
|
309
|
+
if (index > -1) {
|
|
310
|
+
this.listeners.splice(index, 1);
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
connect() {
|
|
315
|
+
return Promise.resolve();
|
|
316
|
+
}
|
|
317
|
+
disconnect() {
|
|
318
|
+
this.listeners = [];
|
|
319
|
+
if (this.channel) {
|
|
320
|
+
this.channel.close();
|
|
321
|
+
this.channel = null;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
isConnected() {
|
|
325
|
+
return this.channel !== null;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
function createSyncAdapter() {
|
|
329
|
+
if (typeof chrome !== "undefined" && chrome.runtime) {
|
|
330
|
+
return new ChromeRuntimeSyncAdapter;
|
|
331
|
+
}
|
|
332
|
+
if (typeof BroadcastChannel !== "undefined") {
|
|
333
|
+
return new BroadcastChannelSyncAdapter;
|
|
334
|
+
}
|
|
335
|
+
return new NoOpSyncAdapter;
|
|
336
|
+
}
|
|
337
|
+
|
|
51
338
|
// src/shared/lib/constraints.ts
|
|
52
339
|
var exports_constraints = {};
|
|
53
340
|
__export(exports_constraints, {
|
|
@@ -413,8 +700,60 @@ class MessageLoggerAdapter {
|
|
|
413
700
|
}
|
|
414
701
|
}
|
|
415
702
|
|
|
703
|
+
// src/shared/lib/adapter-factory.ts
|
|
704
|
+
function createStateAdapters(options = {}) {
|
|
705
|
+
if (options.storage && options.sync) {
|
|
706
|
+
return {
|
|
707
|
+
storage: options.storage,
|
|
708
|
+
sync: options.sync
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
const storage = options.storage || createStorageAdapter();
|
|
712
|
+
let sync;
|
|
713
|
+
if (options.sync) {
|
|
714
|
+
sync = options.sync;
|
|
715
|
+
} else if (options.singleTab) {
|
|
716
|
+
const { NoOpSyncAdapter: NoOpSyncAdapter2 } = __toCommonJS(exports_sync_adapter);
|
|
717
|
+
sync = new NoOpSyncAdapter2;
|
|
718
|
+
} else {
|
|
719
|
+
sync = createSyncAdapter();
|
|
720
|
+
}
|
|
721
|
+
return { storage, sync };
|
|
722
|
+
}
|
|
723
|
+
function createChromeAdapters() {
|
|
724
|
+
const { ChromeStorageAdapter: ChromeStorageAdapter3 } = __toCommonJS(exports_storage_adapter);
|
|
725
|
+
const { ChromeRuntimeSyncAdapter: ChromeRuntimeSyncAdapter2 } = __toCommonJS(exports_sync_adapter);
|
|
726
|
+
return {
|
|
727
|
+
storage: new ChromeStorageAdapter3,
|
|
728
|
+
sync: new ChromeRuntimeSyncAdapter2
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
function createWebAdapters(options = {}) {
|
|
732
|
+
const { IndexedDBAdapter: IndexedDBAdapter2 } = __toCommonJS(exports_storage_adapter);
|
|
733
|
+
const { BroadcastChannelSyncAdapter: BroadcastChannelSyncAdapter2, NoOpSyncAdapter: NoOpSyncAdapter2 } = __toCommonJS(exports_sync_adapter);
|
|
734
|
+
const storage = new IndexedDBAdapter2(options.dbName);
|
|
735
|
+
const sync = options.singleTab ? new NoOpSyncAdapter2 : new BroadcastChannelSyncAdapter2(options.channelName);
|
|
736
|
+
return { storage, sync };
|
|
737
|
+
}
|
|
738
|
+
function createNodeAdapters() {
|
|
739
|
+
const { MemoryStorageAdapter: MemoryStorageAdapter2 } = __toCommonJS(exports_storage_adapter);
|
|
740
|
+
const { NoOpSyncAdapter: NoOpSyncAdapter2 } = __toCommonJS(exports_sync_adapter);
|
|
741
|
+
return {
|
|
742
|
+
storage: new MemoryStorageAdapter2,
|
|
743
|
+
sync: new NoOpSyncAdapter2
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
function createMockAdapters() {
|
|
747
|
+
const { MemoryStorageAdapter: MemoryStorageAdapter2 } = __toCommonJS(exports_storage_adapter);
|
|
748
|
+
const { NoOpSyncAdapter: NoOpSyncAdapter2 } = __toCommonJS(exports_sync_adapter);
|
|
749
|
+
return {
|
|
750
|
+
storage: new MemoryStorageAdapter2,
|
|
751
|
+
sync: new NoOpSyncAdapter2
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
|
|
416
755
|
// src/shared/adapters/index.ts
|
|
417
|
-
function
|
|
756
|
+
function createChromeAdapters2(context, options) {
|
|
418
757
|
const runtime2 = new ChromeRuntimeAdapter;
|
|
419
758
|
return {
|
|
420
759
|
runtime: runtime2,
|
|
@@ -812,7 +1151,7 @@ class MessageBus {
|
|
|
812
1151
|
messageListener = null;
|
|
813
1152
|
constructor(context, adapters, options) {
|
|
814
1153
|
this.context = context;
|
|
815
|
-
this.adapters = adapters ||
|
|
1154
|
+
this.adapters = adapters || createChromeAdapters2(context);
|
|
816
1155
|
this.errorHandler = new ErrorHandler(this.adapters.logger);
|
|
817
1156
|
this.helpers = this.createContextHelpers();
|
|
818
1157
|
if (!options?.skipListenerSetup) {
|
|
@@ -1257,41 +1596,11 @@ function runInContext(context, contexts, fn, adapters) {
|
|
|
1257
1596
|
// src/shared/lib/state.ts
|
|
1258
1597
|
import { effect, signal } from "@preact/signals";
|
|
1259
1598
|
var stateRegistry = new Map;
|
|
1260
|
-
function getCurrentContext() {
|
|
1261
|
-
if (typeof chrome !== "undefined") {
|
|
1262
|
-
if (typeof chrome.devtools !== "undefined") {
|
|
1263
|
-
return "devtools";
|
|
1264
|
-
}
|
|
1265
|
-
if (typeof chrome.runtime !== "undefined") {
|
|
1266
|
-
try {
|
|
1267
|
-
if (typeof self !== "undefined" && "ServiceWorkerGlobalScope" in self) {
|
|
1268
|
-
return "background";
|
|
1269
|
-
}
|
|
1270
|
-
} catch {}
|
|
1271
|
-
}
|
|
1272
|
-
}
|
|
1273
|
-
if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
1274
|
-
if (typeof chrome === "undefined" || typeof chrome.runtime === "undefined") {
|
|
1275
|
-
return "page";
|
|
1276
|
-
}
|
|
1277
|
-
if (typeof window.location !== "undefined" && window.location.protocol === "chrome-extension:") {
|
|
1278
|
-
const path = window.location.pathname;
|
|
1279
|
-
if (path.includes("/popup"))
|
|
1280
|
-
return "popup";
|
|
1281
|
-
if (path.includes("/options"))
|
|
1282
|
-
return "options";
|
|
1283
|
-
if (path.includes("/offscreen"))
|
|
1284
|
-
return "offscreen";
|
|
1285
|
-
}
|
|
1286
|
-
return "content";
|
|
1287
|
-
}
|
|
1288
|
-
return "background";
|
|
1289
|
-
}
|
|
1290
1599
|
function $sharedState(key, initialValue, options = {}) {
|
|
1291
1600
|
const sig = createState(key, initialValue, {
|
|
1292
1601
|
...options,
|
|
1293
|
-
|
|
1294
|
-
|
|
1602
|
+
enableSync: true,
|
|
1603
|
+
enablePersist: true
|
|
1295
1604
|
});
|
|
1296
1605
|
const entry = stateRegistry.get(key);
|
|
1297
1606
|
if (entry) {
|
|
@@ -1302,15 +1611,15 @@ function $sharedState(key, initialValue, options = {}) {
|
|
|
1302
1611
|
function $syncedState(key, initialValue, options = {}) {
|
|
1303
1612
|
return createState(key, initialValue, {
|
|
1304
1613
|
...options,
|
|
1305
|
-
|
|
1306
|
-
|
|
1614
|
+
enableSync: true,
|
|
1615
|
+
enablePersist: false
|
|
1307
1616
|
});
|
|
1308
1617
|
}
|
|
1309
1618
|
function $persistedState(key, initialValue, options = {}) {
|
|
1310
1619
|
const sig = createState(key, initialValue, {
|
|
1311
1620
|
...options,
|
|
1312
|
-
|
|
1313
|
-
|
|
1621
|
+
enableSync: false,
|
|
1622
|
+
enablePersist: true
|
|
1314
1623
|
});
|
|
1315
1624
|
const entry = stateRegistry.get(key);
|
|
1316
1625
|
if (entry) {
|
|
@@ -1340,17 +1649,28 @@ function deepEqual(a, b) {
|
|
|
1340
1649
|
}
|
|
1341
1650
|
return true;
|
|
1342
1651
|
}
|
|
1652
|
+
function resolveAdapters(options) {
|
|
1653
|
+
if (options.storage || options.sync) {
|
|
1654
|
+
return {
|
|
1655
|
+
storage: options.storage || (options.enablePersist ? createStorageAdapter() : null),
|
|
1656
|
+
sync: options.sync || (options.enableSync ? createSyncAdapter() : null)
|
|
1657
|
+
};
|
|
1658
|
+
}
|
|
1659
|
+
if (options.bus) {
|
|
1660
|
+
return {
|
|
1661
|
+
storage: options.bus.adapters.storage,
|
|
1662
|
+
sync: options.enableSync ? createSyncAdapter() : null
|
|
1663
|
+
};
|
|
1664
|
+
}
|
|
1665
|
+
return {
|
|
1666
|
+
storage: options.enablePersist ? createStorageAdapter() : null,
|
|
1667
|
+
sync: options.enableSync ? createSyncAdapter() : null
|
|
1668
|
+
};
|
|
1669
|
+
}
|
|
1343
1670
|
function createState(key, initialValue, options) {
|
|
1344
1671
|
if (stateRegistry.has(key)) {
|
|
1345
1672
|
return stateRegistry.get(key)?.signal;
|
|
1346
1673
|
}
|
|
1347
|
-
const currentContext = getCurrentContext();
|
|
1348
|
-
if (currentContext === "page" && (options.sync || options.persist)) {
|
|
1349
|
-
const stateFn = options.sync && options.persist ? "$sharedState" : options.persist ? "$persistedState" : "$syncedState";
|
|
1350
|
-
throw new Error(`[web-ext] ${stateFn}() is not available in page context.
|
|
1351
|
-
Page scripts are execution contexts for content scripts and should not maintain state.
|
|
1352
|
-
Use state in the content script instead, or use $state() for local-only state.`);
|
|
1353
|
-
}
|
|
1354
1674
|
const sig = signal(initialValue);
|
|
1355
1675
|
if (options.verify) {
|
|
1356
1676
|
const mirror = JSON.parse(JSON.stringify(initialValue));
|
|
@@ -1362,15 +1682,9 @@ Use state in the content script instead, or use $state() for local-only state.`)
|
|
|
1362
1682
|
loaded: Promise.resolve(),
|
|
1363
1683
|
updating: false
|
|
1364
1684
|
};
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
bus = options.bus || getMessageBus(currentContext);
|
|
1369
|
-
}
|
|
1370
|
-
return bus;
|
|
1371
|
-
};
|
|
1372
|
-
if (options.persist) {
|
|
1373
|
-
entry.loaded = loadFromStorage(key, sig, entry, getBus(), options.validator);
|
|
1685
|
+
const adapters = resolveAdapters(options);
|
|
1686
|
+
if (options.enablePersist && adapters.storage) {
|
|
1687
|
+
entry.loaded = loadFromStorage(key, sig, entry, adapters.storage, options.validator);
|
|
1374
1688
|
}
|
|
1375
1689
|
entry.loaded.then(() => {
|
|
1376
1690
|
let debounceTimer = null;
|
|
@@ -1396,11 +1710,11 @@ Use state in the content script instead, or use $state() for local-only state.`)
|
|
|
1396
1710
|
}
|
|
1397
1711
|
entry.clock++;
|
|
1398
1712
|
const doUpdate = () => {
|
|
1399
|
-
if (options.
|
|
1400
|
-
persistToStorage(key, value, entry.clock,
|
|
1713
|
+
if (options.enablePersist && adapters.storage) {
|
|
1714
|
+
persistToStorage(key, value, entry.clock, adapters.storage);
|
|
1401
1715
|
}
|
|
1402
|
-
if (options.sync) {
|
|
1403
|
-
broadcastUpdate(key, value, entry.clock,
|
|
1716
|
+
if (options.enableSync && adapters.sync) {
|
|
1717
|
+
broadcastUpdate(key, value, entry.clock, adapters.sync);
|
|
1404
1718
|
}
|
|
1405
1719
|
};
|
|
1406
1720
|
if (options.debounceMs) {
|
|
@@ -1412,46 +1726,40 @@ Use state in the content script instead, or use $state() for local-only state.`)
|
|
|
1412
1726
|
}
|
|
1413
1727
|
});
|
|
1414
1728
|
});
|
|
1415
|
-
if (options.sync) {
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1729
|
+
if (options.enableSync && adapters.sync) {
|
|
1730
|
+
if (adapters.sync.connect) {
|
|
1731
|
+
adapters.sync.connect();
|
|
1732
|
+
}
|
|
1733
|
+
adapters.sync.onMessage((message) => {
|
|
1734
|
+
if (message.key !== key)
|
|
1735
|
+
return;
|
|
1736
|
+
const oldClock = entry.clock;
|
|
1737
|
+
entry.clock = Math.max(entry.clock, message.clock);
|
|
1738
|
+
if (message.clock > oldClock) {
|
|
1739
|
+
if (options.validator && !options.validator(message.value)) {
|
|
1740
|
+
console.warn(`[Polly] State "${key}": Received invalid value from sync (clock: ${message.clock})`, message.value);
|
|
1423
1741
|
return;
|
|
1424
|
-
const oldClock = entry.clock;
|
|
1425
|
-
entry.clock = Math.max(entry.clock, payload.clock);
|
|
1426
|
-
if (payload.clock > oldClock) {
|
|
1427
|
-
if (options.validator && !options.validator(payload.value)) {
|
|
1428
|
-
console.warn(`[web-ext] State "${key}": Received invalid value from sync (clock: ${payload.clock})`, payload.value);
|
|
1429
|
-
return;
|
|
1430
|
-
}
|
|
1431
|
-
if (deepEqual(entry.signal.value, payload.value)) {
|
|
1432
|
-
return;
|
|
1433
|
-
}
|
|
1434
|
-
applyUpdate(entry, payload.value, payload.clock);
|
|
1435
1742
|
}
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1743
|
+
if (deepEqual(entry.signal.value, message.value)) {
|
|
1744
|
+
return;
|
|
1745
|
+
}
|
|
1746
|
+
applyUpdate(entry, message.value, message.clock);
|
|
1747
|
+
}
|
|
1748
|
+
});
|
|
1439
1749
|
}
|
|
1440
1750
|
stateRegistry.set(key, entry);
|
|
1441
1751
|
return sig;
|
|
1442
1752
|
}
|
|
1443
|
-
async function loadFromStorage(key, sig, entry,
|
|
1444
|
-
if (!bus)
|
|
1445
|
-
return;
|
|
1753
|
+
async function loadFromStorage(key, sig, entry, storage2, validator) {
|
|
1446
1754
|
try {
|
|
1447
|
-
const result = await
|
|
1755
|
+
const result = await storage2.get([key, `${key}:clock`]);
|
|
1448
1756
|
if (result[key] !== undefined) {
|
|
1449
1757
|
const storedValue = result[key];
|
|
1450
1758
|
if (validator) {
|
|
1451
1759
|
if (validator(storedValue)) {
|
|
1452
1760
|
sig.value = storedValue;
|
|
1453
1761
|
} else {
|
|
1454
|
-
console.warn(`[
|
|
1762
|
+
console.warn(`[Polly] State "${key}": Stored value failed validation, using initial value`, storedValue);
|
|
1455
1763
|
}
|
|
1456
1764
|
} else {
|
|
1457
1765
|
sig.value = storedValue;
|
|
@@ -1461,33 +1769,28 @@ async function loadFromStorage(key, sig, entry, bus, validator) {
|
|
|
1461
1769
|
entry.clock = result[`${key}:clock`];
|
|
1462
1770
|
}
|
|
1463
1771
|
} catch (error) {
|
|
1464
|
-
console.warn(`[
|
|
1772
|
+
console.warn(`[Polly] Failed to load state from storage: ${key}`, error);
|
|
1465
1773
|
}
|
|
1466
1774
|
}
|
|
1467
|
-
function persistToStorage(key, value, clock,
|
|
1468
|
-
if (!bus)
|
|
1469
|
-
return;
|
|
1775
|
+
function persistToStorage(key, value, clock, storage2) {
|
|
1470
1776
|
try {
|
|
1471
|
-
|
|
1777
|
+
storage2.set({
|
|
1472
1778
|
[key]: value,
|
|
1473
1779
|
[`${key}:clock`]: clock
|
|
1474
1780
|
});
|
|
1475
1781
|
} catch (error) {
|
|
1476
|
-
console.warn(`Failed to persist state to storage: ${key}`, error);
|
|
1782
|
+
console.warn(`[Polly] Failed to persist state to storage: ${key}`, error);
|
|
1477
1783
|
}
|
|
1478
1784
|
}
|
|
1479
|
-
function broadcastUpdate(key, value, clock,
|
|
1480
|
-
if (!bus)
|
|
1481
|
-
return;
|
|
1785
|
+
function broadcastUpdate(key, value, clock, sync) {
|
|
1482
1786
|
try {
|
|
1483
|
-
|
|
1484
|
-
type: "STATE_SYNC",
|
|
1787
|
+
sync.broadcast({
|
|
1485
1788
|
key,
|
|
1486
1789
|
value,
|
|
1487
1790
|
clock
|
|
1488
1791
|
});
|
|
1489
1792
|
} catch (error) {
|
|
1490
|
-
console.warn(`Failed to broadcast state update: ${key}`, error);
|
|
1793
|
+
console.warn(`[Polly] Failed to broadcast state update: ${key}`, error);
|
|
1491
1794
|
}
|
|
1492
1795
|
}
|
|
1493
1796
|
function applyUpdate(entry, value, clock) {
|
|
@@ -1709,7 +2012,7 @@ export {
|
|
|
1709
2012
|
getMessageBus,
|
|
1710
2013
|
createTestSuite,
|
|
1711
2014
|
createContext,
|
|
1712
|
-
createChromeAdapters,
|
|
2015
|
+
createChromeAdapters2 as createChromeAdapters,
|
|
1713
2016
|
clearConstraints,
|
|
1714
2017
|
checkPreconditions,
|
|
1715
2018
|
checkPostconditions,
|
|
@@ -1726,4 +2029,4 @@ export {
|
|
|
1726
2029
|
$persistedState
|
|
1727
2030
|
};
|
|
1728
2031
|
|
|
1729
|
-
//# debugId=
|
|
2032
|
+
//# debugId=2C9C410817D4600B64756E2164756E21
|