@fairfox/polly 0.12.3 → 0.13.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 +118 -1
- package/dist/src/background/index.js.map +5 -4
- package/dist/src/background/message-router.js +118 -1
- package/dist/src/background/message-router.js.map +5 -4
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +203 -3
- package/dist/src/index.js.map +9 -6
- package/dist/src/shared/lib/constraints.d.ts +61 -0
- package/dist/src/shared/lib/context-helpers.js +118 -1
- package/dist/src/shared/lib/context-helpers.js.map +5 -4
- package/dist/src/shared/lib/message-bus.d.ts +22 -0
- package/dist/src/shared/lib/message-bus.js +118 -1
- package/dist/src/shared/lib/message-bus.js.map +5 -4
- package/dist/src/shared/lib/state.d.ts +8 -2
- package/dist/src/shared/lib/state.js +140 -3
- package/dist/src/shared/lib/state.js.map +6 -5
- package/dist/src/shared/lib/validation.d.ts +94 -0
- package/dist/src/shared/state/app-state.d.ts +4 -1
- package/dist/src/shared/state/app-state.js +140 -3
- package/dist/src/shared/state/app-state.js.map +6 -5
- package/dist/tools/analysis/src/extract/handlers.d.ts +24 -2
- package/dist/tools/teach/src/cli.js +102 -17
- package/dist/tools/teach/src/cli.js.map +3 -3
- package/dist/tools/teach/src/index.js +102 -17
- package/dist/tools/teach/src/index.js.map +3 -3
- package/dist/tools/verify/Dockerfile +11 -7
- package/dist/tools/verify/specs/Dockerfile +21 -5
- package/dist/tools/verify/specs/README.md +13 -6
- package/dist/tools/verify/src/cli.js +102 -17
- package/dist/tools/verify/src/cli.js.map +3 -3
- package/dist/tools/verify/src/config.js +8 -2
- package/dist/tools/verify/src/config.js.map +3 -3
- package/dist/tools/verify/src/primitives/index.d.ts +21 -8
- package/dist/tools/visualize/src/cli.js +102 -17
- package/dist/tools/visualize/src/cli.js.map +3 -3
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -48,6 +48,90 @@ 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/constraints.ts
|
|
52
|
+
var exports_constraints = {};
|
|
53
|
+
__export(exports_constraints, {
|
|
54
|
+
registerConstraints: () => registerConstraints,
|
|
55
|
+
registerConstraint: () => registerConstraint,
|
|
56
|
+
isRuntimeConstraintsEnabled: () => isRuntimeConstraintsEnabled,
|
|
57
|
+
getRegisteredConstraints: () => getRegisteredConstraints,
|
|
58
|
+
clearConstraints: () => clearConstraints,
|
|
59
|
+
checkPreconditions: () => checkPreconditions,
|
|
60
|
+
checkPostconditions: () => checkPostconditions
|
|
61
|
+
});
|
|
62
|
+
function registerConstraint(field, messageType, constraint) {
|
|
63
|
+
if (!registry.has(field)) {
|
|
64
|
+
registry.set(field, new Map);
|
|
65
|
+
}
|
|
66
|
+
registry.get(field)?.set(messageType, constraint);
|
|
67
|
+
}
|
|
68
|
+
function registerConstraints(field, constraints) {
|
|
69
|
+
for (const [messageType, constraint] of Object.entries(constraints)) {
|
|
70
|
+
const runtimeConstraint = {
|
|
71
|
+
message: constraint.message
|
|
72
|
+
};
|
|
73
|
+
if (typeof constraint.requires === "function") {
|
|
74
|
+
runtimeConstraint.requires = constraint.requires;
|
|
75
|
+
}
|
|
76
|
+
if (typeof constraint.ensures === "function") {
|
|
77
|
+
runtimeConstraint.ensures = constraint.ensures;
|
|
78
|
+
}
|
|
79
|
+
if (runtimeConstraint.requires || runtimeConstraint.ensures) {
|
|
80
|
+
registerConstraint(field, messageType, runtimeConstraint);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function executeConstraint(predicate, state, messageType, field, customMessage, constraintType = "Precondition") {
|
|
85
|
+
try {
|
|
86
|
+
const result = predicate(state);
|
|
87
|
+
if (!result) {
|
|
88
|
+
const message = customMessage || `${constraintType} failed for ${messageType} on field ${field}`;
|
|
89
|
+
throw new Error(message);
|
|
90
|
+
}
|
|
91
|
+
} catch (error) {
|
|
92
|
+
if (error instanceof Error && error.message.includes(`${constraintType} failed`)) {
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
const message = customMessage || `${constraintType} check error for ${messageType} on field ${field}`;
|
|
96
|
+
throw new Error(`${message}: ${error}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function checkPreconditions(messageType, state) {
|
|
100
|
+
for (const [field, constraints] of registry) {
|
|
101
|
+
const constraint = constraints.get(messageType);
|
|
102
|
+
if (constraint?.requires) {
|
|
103
|
+
executeConstraint(constraint.requires, state, messageType, field, constraint.message, "Precondition");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function checkPostconditions(messageType, state) {
|
|
108
|
+
for (const [field, constraints] of registry) {
|
|
109
|
+
const constraint = constraints.get(messageType);
|
|
110
|
+
if (constraint?.ensures) {
|
|
111
|
+
executeConstraint(constraint.ensures, state, messageType, field, constraint.message, "Postcondition");
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function clearConstraints() {
|
|
116
|
+
registry.clear();
|
|
117
|
+
}
|
|
118
|
+
function getRegisteredConstraints() {
|
|
119
|
+
return new Map(registry);
|
|
120
|
+
}
|
|
121
|
+
function isRuntimeConstraintsEnabled() {
|
|
122
|
+
if (typeof process !== "undefined" && process.env) {
|
|
123
|
+
return process.env["POLLY_RUNTIME_CONSTRAINTS"] === "true";
|
|
124
|
+
}
|
|
125
|
+
if (typeof Bun !== "undefined" && Bun.env) {
|
|
126
|
+
return Bun.env["POLLY_RUNTIME_CONSTRAINTS"] === "true";
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
var registry;
|
|
131
|
+
var init_constraints = __esm(() => {
|
|
132
|
+
registry = new Map;
|
|
133
|
+
});
|
|
134
|
+
|
|
51
135
|
// src/shared/adapters/chrome/context-menus.chrome.ts
|
|
52
136
|
class ChromeContextMenusAdapter {
|
|
53
137
|
async create(createProperties) {
|
|
@@ -724,6 +808,7 @@ class MessageBus {
|
|
|
724
808
|
port = null;
|
|
725
809
|
errorHandler;
|
|
726
810
|
userErrorHandlers = [];
|
|
811
|
+
stateAccessor = null;
|
|
727
812
|
messageListener = null;
|
|
728
813
|
constructor(context, adapters, options) {
|
|
729
814
|
this.context = context;
|
|
@@ -811,6 +896,9 @@ class MessageBus {
|
|
|
811
896
|
onError(handler) {
|
|
812
897
|
this.userErrorHandlers.push(handler);
|
|
813
898
|
}
|
|
899
|
+
setStateAccessor(accessor) {
|
|
900
|
+
this.stateAccessor = accessor;
|
|
901
|
+
}
|
|
814
902
|
async sendToBackground(payload, options) {
|
|
815
903
|
return this.send(payload, { ...options, target: "background" });
|
|
816
904
|
}
|
|
@@ -968,11 +1056,40 @@ class MessageBus {
|
|
|
968
1056
|
}
|
|
969
1057
|
try {
|
|
970
1058
|
globalExecutionTracker.track(message.id, message.payload.type);
|
|
1059
|
+
if (this.stateAccessor) {
|
|
1060
|
+
try {
|
|
1061
|
+
const { checkPreconditions: checkPreconditions2, isRuntimeConstraintsEnabled: isRuntimeConstraintsEnabled2 } = await Promise.resolve().then(() => (init_constraints(), exports_constraints));
|
|
1062
|
+
if (isRuntimeConstraintsEnabled2()) {
|
|
1063
|
+
const currentState = this.stateAccessor();
|
|
1064
|
+
checkPreconditions2(message.payload.type, currentState);
|
|
1065
|
+
}
|
|
1066
|
+
} catch (error) {
|
|
1067
|
+
if (error instanceof Error) {
|
|
1068
|
+
throw error;
|
|
1069
|
+
}
|
|
1070
|
+
if (error && typeof error === "object" && "code" in error && error.code === "MODULE_NOT_FOUND") {} else {
|
|
1071
|
+
throw error;
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
971
1075
|
const handler = handlers[0];
|
|
972
1076
|
if (!handler) {
|
|
973
1077
|
throw new Error(`Handler not found for ${message.payload.type}`);
|
|
974
1078
|
}
|
|
975
1079
|
const data = await handler(message.payload, message);
|
|
1080
|
+
if (this.stateAccessor) {
|
|
1081
|
+
try {
|
|
1082
|
+
const { checkPostconditions: checkPostconditions2, isRuntimeConstraintsEnabled: isRuntimeConstraintsEnabled2 } = await Promise.resolve().then(() => (init_constraints(), exports_constraints));
|
|
1083
|
+
if (isRuntimeConstraintsEnabled2()) {
|
|
1084
|
+
const currentState = this.stateAccessor();
|
|
1085
|
+
checkPostconditions2(message.payload.type, currentState);
|
|
1086
|
+
}
|
|
1087
|
+
} catch (error) {
|
|
1088
|
+
if (error instanceof Error && error.message.includes("Postcondition")) {
|
|
1089
|
+
console.error(`[${this.context}] Postcondition failed:`, error.message);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
976
1093
|
const response = {
|
|
977
1094
|
id: message.id,
|
|
978
1095
|
success: true,
|
|
@@ -1170,11 +1287,16 @@ function getCurrentContext() {
|
|
|
1170
1287
|
return "background";
|
|
1171
1288
|
}
|
|
1172
1289
|
function $sharedState(key, initialValue, options = {}) {
|
|
1173
|
-
|
|
1290
|
+
const sig = createState(key, initialValue, {
|
|
1174
1291
|
...options,
|
|
1175
1292
|
sync: true,
|
|
1176
1293
|
persist: true
|
|
1177
1294
|
});
|
|
1295
|
+
const entry = stateRegistry.get(key);
|
|
1296
|
+
if (entry) {
|
|
1297
|
+
sig.loaded = entry.loaded;
|
|
1298
|
+
}
|
|
1299
|
+
return sig;
|
|
1178
1300
|
}
|
|
1179
1301
|
function $syncedState(key, initialValue, options = {}) {
|
|
1180
1302
|
return createState(key, initialValue, {
|
|
@@ -1184,11 +1306,16 @@ function $syncedState(key, initialValue, options = {}) {
|
|
|
1184
1306
|
});
|
|
1185
1307
|
}
|
|
1186
1308
|
function $persistedState(key, initialValue, options = {}) {
|
|
1187
|
-
|
|
1309
|
+
const sig = createState(key, initialValue, {
|
|
1188
1310
|
...options,
|
|
1189
1311
|
sync: false,
|
|
1190
1312
|
persist: true
|
|
1191
1313
|
});
|
|
1314
|
+
const entry = stateRegistry.get(key);
|
|
1315
|
+
if (entry) {
|
|
1316
|
+
sig.loaded = entry.loaded;
|
|
1317
|
+
}
|
|
1318
|
+
return sig;
|
|
1192
1319
|
}
|
|
1193
1320
|
function $state(initialValue) {
|
|
1194
1321
|
return signal(initialValue);
|
|
@@ -1224,6 +1351,10 @@ Page scripts are execution contexts for content scripts and should not maintain
|
|
|
1224
1351
|
Use state in the content script instead, or use $state() for local-only state.`);
|
|
1225
1352
|
}
|
|
1226
1353
|
const sig = signal(initialValue);
|
|
1354
|
+
if (options.verify) {
|
|
1355
|
+
const mirror = JSON.parse(JSON.stringify(initialValue));
|
|
1356
|
+
sig.verify = mirror;
|
|
1357
|
+
}
|
|
1227
1358
|
const entry = {
|
|
1228
1359
|
signal: sig,
|
|
1229
1360
|
clock: 0,
|
|
@@ -1256,6 +1387,12 @@ Use state in the content script instead, or use $state() for local-only state.`)
|
|
|
1256
1387
|
return;
|
|
1257
1388
|
}
|
|
1258
1389
|
previousValue = value;
|
|
1390
|
+
if (options.verify) {
|
|
1391
|
+
const verifySignal = sig;
|
|
1392
|
+
if (verifySignal.verify) {
|
|
1393
|
+
Object.assign(verifySignal.verify, JSON.parse(JSON.stringify(value)));
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1259
1396
|
entry.clock++;
|
|
1260
1397
|
const doUpdate = () => {
|
|
1261
1398
|
if (options.persist) {
|
|
@@ -1504,14 +1641,77 @@ var uiState = signal2({
|
|
|
1504
1641
|
sidebarOpen: false,
|
|
1505
1642
|
selectedPanel: "main"
|
|
1506
1643
|
});
|
|
1644
|
+
|
|
1645
|
+
// src/index.ts
|
|
1646
|
+
init_constraints();
|
|
1647
|
+
|
|
1648
|
+
// src/shared/lib/validation.ts
|
|
1649
|
+
function checkPrimitiveType(val, type) {
|
|
1650
|
+
if (type === "array")
|
|
1651
|
+
return Array.isArray(val);
|
|
1652
|
+
if (type === "null")
|
|
1653
|
+
return val === null;
|
|
1654
|
+
if (type === "undefined")
|
|
1655
|
+
return val === undefined;
|
|
1656
|
+
return typeof val === type;
|
|
1657
|
+
}
|
|
1658
|
+
function checkFieldType(val, type) {
|
|
1659
|
+
if (typeof type === "string") {
|
|
1660
|
+
return checkPrimitiveType(val, type);
|
|
1661
|
+
}
|
|
1662
|
+
return validateShape(type)(val);
|
|
1663
|
+
}
|
|
1664
|
+
function validateShape(shape) {
|
|
1665
|
+
return (value) => {
|
|
1666
|
+
if (typeof value !== "object" || value === null)
|
|
1667
|
+
return false;
|
|
1668
|
+
const obj = value;
|
|
1669
|
+
for (const [key, type] of Object.entries(shape)) {
|
|
1670
|
+
if (!(key in obj))
|
|
1671
|
+
return false;
|
|
1672
|
+
if (!checkFieldType(obj[key], type))
|
|
1673
|
+
return false;
|
|
1674
|
+
}
|
|
1675
|
+
return true;
|
|
1676
|
+
};
|
|
1677
|
+
}
|
|
1678
|
+
function validateEnum(allowed) {
|
|
1679
|
+
return (value) => {
|
|
1680
|
+
return allowed.includes(value);
|
|
1681
|
+
};
|
|
1682
|
+
}
|
|
1683
|
+
function validateArray(itemValidator) {
|
|
1684
|
+
return (value) => {
|
|
1685
|
+
if (!Array.isArray(value))
|
|
1686
|
+
return false;
|
|
1687
|
+
return value.every(itemValidator);
|
|
1688
|
+
};
|
|
1689
|
+
}
|
|
1690
|
+
function validatePartial(_validator) {
|
|
1691
|
+
return (value) => {
|
|
1692
|
+
if (typeof value !== "object" || value === null)
|
|
1693
|
+
return false;
|
|
1694
|
+
return true;
|
|
1695
|
+
};
|
|
1696
|
+
}
|
|
1507
1697
|
export {
|
|
1698
|
+
validateShape,
|
|
1699
|
+
validatePartial,
|
|
1700
|
+
validateEnum,
|
|
1701
|
+
validateArray,
|
|
1508
1702
|
settings,
|
|
1509
1703
|
runInContext,
|
|
1704
|
+
registerConstraints,
|
|
1705
|
+
registerConstraint,
|
|
1510
1706
|
quickTest,
|
|
1707
|
+
isRuntimeConstraintsEnabled,
|
|
1511
1708
|
getMessageBus,
|
|
1512
1709
|
createTestSuite,
|
|
1513
1710
|
createContext,
|
|
1514
1711
|
createChromeAdapters,
|
|
1712
|
+
clearConstraints,
|
|
1713
|
+
checkPreconditions,
|
|
1714
|
+
checkPostconditions,
|
|
1515
1715
|
TimeoutError,
|
|
1516
1716
|
TestRunner,
|
|
1517
1717
|
MessageBus,
|
|
@@ -1525,4 +1725,4 @@ export {
|
|
|
1525
1725
|
$persistedState
|
|
1526
1726
|
};
|
|
1527
1727
|
|
|
1528
|
-
//# debugId=
|
|
1728
|
+
//# debugId=20542B0975865A4164756E2164756E21
|