@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
@@ -27,7 +27,7 @@ class TLAGenerator {
27
27
  this.lines = [];
28
28
  this.indent = 0;
29
29
  const spec = this.generateSpec(config, analysis);
30
- const cfg = this.generateConfig(config, analysis);
30
+ const cfg = this.generateConfig(config);
31
31
  return { spec, cfg };
32
32
  }
33
33
  generateSpec(config, analysis) {
@@ -35,7 +35,7 @@ class TLAGenerator {
35
35
  this.indent = 0;
36
36
  this.addHeader();
37
37
  this.addExtends();
38
- this.addConstants(config, analysis);
38
+ this.addConstants(config);
39
39
  this.addMessageTypes(config, analysis);
40
40
  this.addStateType(config, analysis);
41
41
  this.addVariables();
@@ -48,7 +48,7 @@ class TLAGenerator {
48
48
  return this.lines.join(`
49
49
  `);
50
50
  }
51
- generateConfig(config, analysis) {
51
+ generateConfig(config) {
52
52
  const lines = [];
53
53
  lines.push("SPECIFICATION UserSpec");
54
54
  lines.push("");
@@ -107,8 +107,8 @@ class TLAGenerator {
107
107
  this.line("EXTENDS MessageRouter");
108
108
  this.line("");
109
109
  }
110
- addConstants(config, analysis) {
111
- const hasCustomConstants = Object.entries(config.state).some(([field, fieldConfig]) => {
110
+ addConstants(config) {
111
+ const hasCustomConstants = Object.entries(config.state).some(([_, fieldConfig]) => {
112
112
  if (typeof fieldConfig !== "object" || fieldConfig === null)
113
113
  return false;
114
114
  return "maxLength" in fieldConfig && fieldConfig.maxLength !== null || "max" in fieldConfig && fieldConfig.max !== null || "maxSize" in fieldConfig && fieldConfig.maxSize !== null;
@@ -140,7 +140,7 @@ class TLAGenerator {
140
140
  this.indent--;
141
141
  this.line("");
142
142
  }
143
- addStateType(config, analysis) {
143
+ addStateType(config, _analysis) {
144
144
  this.line("\\* Generic value type for sequences and maps");
145
145
  this.line("\\* Bounded to allow model checking");
146
146
  this.line('Value == {"v1", "v2", "v3"}');
@@ -169,7 +169,7 @@ class TLAGenerator {
169
169
  this.line("]");
170
170
  this.line("");
171
171
  }
172
- addMessageTypes(config, analysis) {
172
+ addMessageTypes(_config, analysis) {
173
173
  if (analysis.messageTypes.length === 0) {
174
174
  return;
175
175
  }
@@ -186,7 +186,7 @@ class TLAGenerator {
186
186
  this.line("allVars == <<ports, messages, pendingRequests, delivered, routingDepth, time, contextStates>>");
187
187
  this.line("");
188
188
  }
189
- addInit(config, analysis) {
189
+ addInit(config, _analysis) {
190
190
  this.line("\\* Initial application state");
191
191
  this.line("InitialState == [");
192
192
  this.indent++;
@@ -247,6 +247,8 @@ class TLAGenerator {
247
247
  const messageTypes = Array.from(handlersByType.keys());
248
248
  for (let i = 0;i < messageTypes.length; i++) {
249
249
  const msgType = messageTypes[i];
250
+ if (!msgType)
251
+ continue;
250
252
  const actionName = this.messageTypeToActionName(msgType);
251
253
  if (i === 0) {
252
254
  this.line(`IF msgType = "${msgType}" THEN ${actionName}(ctx)`);
@@ -304,6 +306,8 @@ class TLAGenerator {
304
306
  this.indent++;
305
307
  for (let i = 0;i < validAssignments.length; i++) {
306
308
  const assignment = validAssignments[i];
309
+ if (!assignment || assignment.value === undefined)
310
+ continue;
307
311
  const fieldName = this.sanitizeFieldName(assignment.field);
308
312
  const value = this.assignmentValueToTLA(assignment.value);
309
313
  const suffix = i < validAssignments.length - 1 ? "," : "";
@@ -325,10 +329,10 @@ class TLAGenerator {
325
329
  tsExpressionToTLA(expr, isPrimed = false) {
326
330
  let tla = expr;
327
331
  const statePrefix = isPrimed ? "contextStates'[ctx]" : "contextStates[ctx]";
328
- tla = tla.replace(/state\.([a-zA-Z_][a-zA-Z0-9_.]*)/g, (match, path2) => {
332
+ tla = tla.replace(/state\.([a-zA-Z_][a-zA-Z0-9_.]*)/g, (_match, path2) => {
329
333
  return `${statePrefix}.${this.sanitizeFieldName(path2)}`;
330
334
  });
331
- tla = tla.replace(/payload\.([a-zA-Z_][a-zA-Z0-9_.]*)/g, (match, path2) => {
335
+ tla = tla.replace(/payload\.([a-zA-Z_][a-zA-Z0-9_.]*)/g, (_match, path2) => {
332
336
  return `payload.${this.sanitizeFieldName(path2)}`;
333
337
  });
334
338
  tla = tla.replace(/===/g, "=");
@@ -366,7 +370,7 @@ class TLAGenerator {
366
370
  }
367
371
  return "NULL";
368
372
  }
369
- addRouteWithHandlers(config, analysis) {
373
+ addRouteWithHandlers(_config, analysis) {
370
374
  this.line("\\* =============================================================================");
371
375
  this.line("\\* Message Routing with State Transitions");
372
376
  this.line("\\* =============================================================================");
@@ -401,7 +405,7 @@ class TLAGenerator {
401
405
  this.indent--;
402
406
  this.line("");
403
407
  }
404
- addNext(config, analysis) {
408
+ addNext(_config, analysis) {
405
409
  this.line("\\* Next state relation (extends MessageRouter)");
406
410
  this.line("UserNext ==");
407
411
  this.indent++;
@@ -426,7 +430,7 @@ class TLAGenerator {
426
430
  this.line("UserSpec == UserInit /\\ [][UserNext]_allVars /\\ WF_allVars(UserNext)");
427
431
  this.line("");
428
432
  }
429
- addInvariants(config, analysis) {
433
+ addInvariants(_config, _analysis) {
430
434
  this.line("\\* =============================================================================");
431
435
  this.line("\\* Application Invariants");
432
436
  this.line("\\* =============================================================================");
@@ -450,7 +454,7 @@ class TLAGenerator {
450
454
  this.line("");
451
455
  this.line("=============================================================================");
452
456
  }
453
- fieldConfigToTLAType(fieldPath, fieldConfig, config) {
457
+ fieldConfigToTLAType(_fieldPath, fieldConfig, _config) {
454
458
  if ("type" in fieldConfig) {
455
459
  if (fieldConfig.type === "boolean") {
456
460
  return "BOOLEAN";
@@ -461,11 +465,9 @@ class TLAGenerator {
461
465
  }
462
466
  }
463
467
  if ("maxLength" in fieldConfig) {
464
- const constName = this.fieldToConstName(fieldPath);
465
468
  return `Seq(Value)`;
466
469
  }
467
470
  if ("min" in fieldConfig && "max" in fieldConfig) {
468
- const constName = this.fieldToConstName(fieldPath);
469
471
  const min = fieldConfig.min || 0;
470
472
  const max = fieldConfig.max || 100;
471
473
  return `${min}..${max}`;
@@ -538,7 +540,6 @@ import * as fs2 from "node:fs";
538
540
  import * as path2 from "node:path";
539
541
 
540
542
  class DockerRunner {
541
- containerName = "web-ext-tla-verify";
542
543
  async isDockerAvailable() {
543
544
  try {
544
545
  const result = await this.runCommand("docker", ["--version"]);
@@ -609,8 +610,8 @@ class DockerRunner {
609
610
  return {
610
611
  success: true,
611
612
  stats: {
612
- statesGenerated: statesMatch ? Number.parseInt(statesMatch[1]) : 0,
613
- distinctStates: distinctMatch ? Number.parseInt(distinctMatch[1]) : 0
613
+ statesGenerated: statesMatch?.[1] ? Number.parseInt(statesMatch[1]) : 0,
614
+ distinctStates: distinctMatch?.[1] ? Number.parseInt(distinctMatch[1]) : 0
614
615
  },
615
616
  output
616
617
  };
@@ -635,7 +636,7 @@ class DockerRunner {
635
636
  }
636
637
  extractError(output) {
637
638
  const errorMatch = output.match(/Error: (.*?)(?:\n|$)/);
638
- if (errorMatch) {
639
+ if (errorMatch?.[1]) {
639
640
  return errorMatch[1];
640
641
  }
641
642
  if (output.includes("Parse Error")) {
@@ -723,7 +724,7 @@ import * as path3 from "node:path";
723
724
  import { Project as Project2 } from "ts-morph";
724
725
 
725
726
  // vendor/analysis/src/extract/handlers.ts
726
- import { Project, SyntaxKind as SyntaxKind2, Node as Node2 } from "ts-morph";
727
+ import { Project, SyntaxKind, Node as Node2 } from "ts-morph";
727
728
 
728
729
  // vendor/analysis/src/extract/relationships.ts
729
730
  import { Node } from "ts-morph";
@@ -826,7 +827,7 @@ class RelationshipExtractor {
826
827
  const objectExpr = expr.getExpression();
827
828
  const objectName = objectExpr.getText();
828
829
  const methodName = expr.getName();
829
- targetComponent = this.inferComponentFromCall(objectName, methodName);
830
+ targetComponent = this.inferComponentFromCall(objectName);
830
831
  if (!targetComponent) {
831
832
  return null;
832
833
  }
@@ -857,7 +858,7 @@ class RelationshipExtractor {
857
858
  rootObject = rootObject.getExpression();
858
859
  }
859
860
  const objectName = rootObject.getText();
860
- const targetComponent = this.inferComponentFromCall(objectName, methodName);
861
+ const targetComponent = this.inferComponentFromCall(objectName);
861
862
  if (!targetComponent) {
862
863
  return null;
863
864
  }
@@ -894,7 +895,7 @@ class RelationshipExtractor {
894
895
  }
895
896
  extractFromFetchCall(callExpr, handlerName) {
896
897
  const args = callExpr.getArguments();
897
- if (args.length === 0) {
898
+ if (args.length === 0 || !args[0]) {
898
899
  return null;
899
900
  }
900
901
  const urlArg = args[0].getText();
@@ -913,7 +914,7 @@ class RelationshipExtractor {
913
914
  evidence: [`fetch() call to: ${urlArg}`]
914
915
  };
915
916
  }
916
- inferComponentFromCall(objectName, methodName) {
917
+ inferComponentFromCall(objectName) {
917
918
  const mappings = {
918
919
  db: "db_client",
919
920
  database: "database",
@@ -990,7 +991,7 @@ class RelationshipExtractor {
990
991
  }
991
992
  if (modulePath.includes("/service") || modulePath.includes("/services")) {
992
993
  const match = modulePath.match(/\/([^/]+)\.ts$/);
993
- if (match) {
994
+ if (match && match[1]) {
994
995
  return this.toComponentId(match[1]);
995
996
  }
996
997
  }
@@ -1075,7 +1076,7 @@ class HandlerExtractor {
1075
1076
  const handlers = [];
1076
1077
  const messageTypes = new Set;
1077
1078
  const sourceFiles = this.project.getSourceFiles();
1078
- if (process.env.POLLY_DEBUG) {
1079
+ if (process.env["POLLY_DEBUG"]) {
1079
1080
  console.log(`[DEBUG] Loaded ${sourceFiles.length} source files`);
1080
1081
  if (sourceFiles.length <= 20) {
1081
1082
  for (const sf of sourceFiles) {
@@ -1090,7 +1091,7 @@ class HandlerExtractor {
1090
1091
  messageTypes.add(handler.messageType);
1091
1092
  }
1092
1093
  }
1093
- if (process.env.POLLY_DEBUG) {
1094
+ if (process.env["POLLY_DEBUG"]) {
1094
1095
  console.log(`[DEBUG] Total handlers extracted: ${handlers.length}`);
1095
1096
  }
1096
1097
  return {
@@ -1207,7 +1208,7 @@ class HandlerExtractor {
1207
1208
  extractVerificationConditions(funcNode, preconditions, postconditions) {
1208
1209
  const body = funcNode.getBody();
1209
1210
  const statements = Node2.isBlock(body) ? body.getStatements() : [body];
1210
- statements.forEach((statement, index) => {
1211
+ statements.forEach((statement) => {
1211
1212
  if (Node2.isExpressionStatement(statement)) {
1212
1213
  const expr = statement.getExpression();
1213
1214
  if (Node2.isCallExpression(expr)) {
@@ -1271,13 +1272,13 @@ class HandlerExtractor {
1271
1272
  if (Node2.isNumericLiteral(node)) {
1272
1273
  return node.getLiteralValue();
1273
1274
  }
1274
- if (node.getKind() === SyntaxKind2.TrueKeyword) {
1275
+ if (node.getKind() === SyntaxKind.TrueKeyword) {
1275
1276
  return true;
1276
1277
  }
1277
- if (node.getKind() === SyntaxKind2.FalseKeyword) {
1278
+ if (node.getKind() === SyntaxKind.FalseKeyword) {
1278
1279
  return false;
1279
1280
  }
1280
- if (node.getKind() === SyntaxKind2.NullKeyword) {
1281
+ if (node.getKind() === SyntaxKind.NullKeyword) {
1281
1282
  return null;
1282
1283
  }
1283
1284
  return;
@@ -1360,7 +1361,7 @@ class HandlerExtractor {
1360
1361
  typeGuards = this.findTypePredicateFunctions(sourceFile);
1361
1362
  this.typeGuardCache.set(sourceFile, typeGuards);
1362
1363
  }
1363
- if (process.env.POLLY_DEBUG) {
1364
+ if (process.env["POLLY_DEBUG"]) {
1364
1365
  console.log(`[DEBUG] File: ${sourceFile.getBaseName()}`);
1365
1366
  console.log(`[DEBUG] Local type guards found: ${typeGuards.size}`);
1366
1367
  if (typeGuards.size > 0) {
@@ -1374,7 +1375,7 @@ class HandlerExtractor {
1374
1375
  const handler = this.extractHandlerFromIfClause(currentIf, typeGuards, context, filePath);
1375
1376
  if (handler) {
1376
1377
  handlers.push(handler);
1377
- if (process.env.POLLY_DEBUG) {
1378
+ if (process.env["POLLY_DEBUG"]) {
1378
1379
  console.log(`[DEBUG] Found handler: ${handler.messageType} at line ${handler.location.line}`);
1379
1380
  }
1380
1381
  }
@@ -1386,7 +1387,7 @@ class HandlerExtractor {
1386
1387
  }
1387
1388
  }
1388
1389
  } catch (error) {
1389
- if (process.env.POLLY_DEBUG) {
1390
+ if (process.env["POLLY_DEBUG"]) {
1390
1391
  console.log(`[DEBUG] Error in extractTypeGuardHandlers: ${error}`);
1391
1392
  }
1392
1393
  }
@@ -1394,7 +1395,8 @@ class HandlerExtractor {
1394
1395
  }
1395
1396
  extractHandlerFromIfClause(ifNode, typeGuards, context, filePath) {
1396
1397
  try {
1397
- const condition = ifNode.getExpression();
1398
+ const ifStmt = ifNode;
1399
+ const condition = ifStmt.getExpression();
1398
1400
  if (!Node2.isCallExpression(condition)) {
1399
1401
  return null;
1400
1402
  }
@@ -1403,32 +1405,32 @@ class HandlerExtractor {
1403
1405
  if (Node2.isIdentifier(funcExpr)) {
1404
1406
  funcName = funcExpr.getText();
1405
1407
  }
1406
- if (process.env.POLLY_DEBUG && funcName) {
1408
+ if (process.env["POLLY_DEBUG"] && funcName) {
1407
1409
  console.log(`[DEBUG] Processing if condition with function: ${funcName}`);
1408
1410
  }
1409
1411
  let messageType = undefined;
1410
1412
  if (funcName && typeGuards.has(funcName)) {
1411
1413
  messageType = typeGuards.get(funcName);
1412
- if (process.env.POLLY_DEBUG) {
1414
+ if (process.env["POLLY_DEBUG"]) {
1413
1415
  console.log(`[DEBUG] Found in local type guards: ${funcName} → ${messageType}`);
1414
1416
  }
1415
1417
  } else if (Node2.isIdentifier(funcExpr)) {
1416
- if (process.env.POLLY_DEBUG) {
1418
+ if (process.env["POLLY_DEBUG"]) {
1417
1419
  console.log(`[DEBUG] Not found locally, trying import resolution for: ${funcName}`);
1418
1420
  }
1419
- messageType = this.resolveImportedTypeGuard(funcExpr);
1421
+ messageType = this.resolveImportedTypeGuard(funcExpr) ?? undefined;
1420
1422
  }
1421
1423
  if (!messageType) {
1422
- if (process.env.POLLY_DEBUG && funcName) {
1424
+ if (process.env["POLLY_DEBUG"] && funcName) {
1423
1425
  console.log(`[DEBUG] Could not resolve message type for: ${funcName}`);
1424
1426
  }
1425
1427
  return null;
1426
1428
  }
1427
- const line = ifNode.getStartLineNumber();
1428
- const sourceFile = ifNode.getSourceFile();
1429
+ const line = ifStmt.getStartLineNumber();
1430
+ const sourceFile = ifStmt.getSourceFile();
1429
1431
  const handlerName = `${messageType}_handler`;
1430
1432
  let relationships = undefined;
1431
- const thenStatement = ifNode.getThenStatement();
1433
+ const thenStatement = ifStmt.getThenStatement();
1432
1434
  if (thenStatement) {
1433
1435
  const detectedRelationships = this.relationshipExtractor.extractFromHandler(thenStatement, sourceFile, handlerName);
1434
1436
  if (detectedRelationships.length > 0) {
@@ -1481,7 +1483,7 @@ class HandlerExtractor {
1481
1483
  const bodyText = body.getText();
1482
1484
  const typeValueMatch = bodyText.match(/\.type\s*===?\s*['"](\w+)['"]/);
1483
1485
  if (typeValueMatch) {
1484
- messageType = typeValueMatch[1];
1486
+ messageType = typeValueMatch[1] ?? null;
1485
1487
  }
1486
1488
  }
1487
1489
  }
@@ -1499,7 +1501,7 @@ class HandlerExtractor {
1499
1501
  const funcName = identifier.getText();
1500
1502
  const definitions = identifier.getDefinitionNodes();
1501
1503
  if (definitions.length === 0) {
1502
- if (process.env.POLLY_DEBUG) {
1504
+ if (process.env["POLLY_DEBUG"]) {
1503
1505
  console.log(`[DEBUG] No definitions found for imported function: ${funcName}`);
1504
1506
  }
1505
1507
  return null;
@@ -1507,7 +1509,7 @@ class HandlerExtractor {
1507
1509
  for (const def of definitions) {
1508
1510
  if (Node2.isFunctionDeclaration(def) || Node2.isFunctionExpression(def) || Node2.isArrowFunction(def)) {
1509
1511
  const returnTypeNode = def.getReturnTypeNode();
1510
- if (process.env.POLLY_DEBUG) {
1512
+ if (process.env["POLLY_DEBUG"]) {
1511
1513
  const returnType = def.getReturnType().getText();
1512
1514
  console.log(`[DEBUG] Function ${funcName} return type (resolved): ${returnType}`);
1513
1515
  console.log(`[DEBUG] Has return type node: ${!!returnTypeNode}`);
@@ -1519,7 +1521,7 @@ class HandlerExtractor {
1519
1521
  const typeName = typeNode.getText();
1520
1522
  const messageType = this.extractMessageTypeFromTypeName(typeName);
1521
1523
  if (messageType) {
1522
- if (process.env.POLLY_DEBUG) {
1524
+ if (process.env["POLLY_DEBUG"]) {
1523
1525
  console.log(`[DEBUG] Resolved ${funcName} → ${messageType} (from AST type predicate)`);
1524
1526
  }
1525
1527
  return messageType;
@@ -1531,8 +1533,8 @@ class HandlerExtractor {
1531
1533
  const bodyText = body.getText();
1532
1534
  const typeValueMatch = bodyText.match(/\.type\s*===?\s*['"](\w+)['"]/);
1533
1535
  if (typeValueMatch) {
1534
- const messageType = typeValueMatch[1];
1535
- if (process.env.POLLY_DEBUG) {
1536
+ const messageType = typeValueMatch[1] ?? null;
1537
+ if (process.env["POLLY_DEBUG"]) {
1536
1538
  console.log(`[DEBUG] Resolved ${funcName} → ${messageType} (from body)`);
1537
1539
  }
1538
1540
  return messageType;
@@ -1541,7 +1543,7 @@ class HandlerExtractor {
1541
1543
  }
1542
1544
  }
1543
1545
  } catch (error) {
1544
- if (process.env.POLLY_DEBUG) {
1546
+ if (process.env["POLLY_DEBUG"]) {
1545
1547
  console.log(`[DEBUG] Error resolving imported type guard: ${error}`);
1546
1548
  }
1547
1549
  }
@@ -1596,7 +1598,7 @@ class TypeExtractor {
1596
1598
  const stateType = stateFilePath ? this.extractStateType(stateFilePath) : this.findStateType();
1597
1599
  const messageTypes = this.findMessageTypes();
1598
1600
  const fields = stateType ? this.analyzeFields(stateType) : [];
1599
- const configFilePath = this.project.getCompilerOptions().configFilePath;
1601
+ const configFilePath = this.project.getCompilerOptions()["configFilePath"];
1600
1602
  const tsConfigPath = typeof configFilePath === "string" ? configFilePath : "tsconfig.json";
1601
1603
  const handlerExtractor = new HandlerExtractor(tsConfigPath);
1602
1604
  const handlerAnalysis = handlerExtractor.extractHandlers();
@@ -1724,10 +1726,13 @@ class TypeExtractor {
1724
1726
  }
1725
1727
  if (type.isObject()) {
1726
1728
  const properties = {};
1727
- for (const prop of type.getProperties()) {
1728
- const propName = prop.getName();
1729
- const propType = prop.getTypeAtLocation(this.project.getSourceFiles()[0]);
1730
- properties[propName] = this.convertType(propType, propName);
1729
+ const sourceFile = this.project.getSourceFiles()[0];
1730
+ if (sourceFile) {
1731
+ for (const prop of type.getProperties()) {
1732
+ const propName = prop.getName();
1733
+ const propType = prop.getTypeAtLocation(sourceFile);
1734
+ properties[propName] = this.convertType(propType, propName);
1735
+ }
1731
1736
  }
1732
1737
  return {
1733
1738
  name,
@@ -1780,7 +1785,7 @@ class TypeExtractor {
1780
1785
  analysis.confidence = "low";
1781
1786
  analysis.suggestions.push("Choose maxLength: 5 (fast), 10 (balanced), or 20 (thorough)");
1782
1787
  analysis.bounds.maxLength = undefined;
1783
- const foundBound = this.findArrayBound(path);
1788
+ const foundBound = this.findArrayBound();
1784
1789
  if (foundBound) {
1785
1790
  analysis.confidence = "medium";
1786
1791
  analysis.evidence.push(`Found array check: ${foundBound.evidence}`);
@@ -1793,7 +1798,7 @@ class TypeExtractor {
1793
1798
  analysis.suggestions.push("Provide min and max values based on your application logic");
1794
1799
  analysis.bounds.min = undefined;
1795
1800
  analysis.bounds.max = undefined;
1796
- const foundBound = this.findNumberBound(path);
1801
+ const foundBound = this.findNumberBound();
1797
1802
  if (foundBound) {
1798
1803
  analysis.confidence = "high";
1799
1804
  analysis.evidence.push(`Found comparison: ${foundBound.evidence}`);
@@ -1815,10 +1820,10 @@ class TypeExtractor {
1815
1820
  }
1816
1821
  return analysis;
1817
1822
  }
1818
- findArrayBound(path) {
1823
+ findArrayBound() {
1819
1824
  return null;
1820
1825
  }
1821
- findNumberBound(path) {
1826
+ findNumberBound() {
1822
1827
  return null;
1823
1828
  }
1824
1829
  }
@@ -1866,7 +1871,7 @@ class ConfigGenerator {
1866
1871
  this.line("");
1867
1872
  }
1868
1873
  addExport() {
1869
- this.line("export default defineVerification({");
1874
+ this.line("export const verificationConfig = defineVerification({");
1870
1875
  this.indent++;
1871
1876
  }
1872
1877
  closeExport() {
@@ -1878,6 +1883,8 @@ class ConfigGenerator {
1878
1883
  this.indent++;
1879
1884
  for (let i = 0;i < fields.length; i++) {
1880
1885
  const field = fields[i];
1886
+ if (!field)
1887
+ continue;
1881
1888
  if (i > 0) {
1882
1889
  this.line("");
1883
1890
  }
@@ -2174,13 +2181,13 @@ class ConfigValidator {
2174
2181
  const lineNumber = source.substring(0, position).split(`
2175
2182
  `).length;
2176
2183
  const line = lines[lineNumber - 1];
2177
- const fieldMatch = line.match(/"([^"]+)":\s*{/);
2184
+ const fieldMatch = line?.match(/"([^"]+)":\s*{/);
2178
2185
  const fieldName = fieldMatch ? fieldMatch[1] : "unknown";
2179
2186
  locations.push({
2180
2187
  line: lineNumber,
2181
2188
  column: match.index - source.lastIndexOf(`
2182
2189
  `, position),
2183
- context: fieldName
2190
+ context: fieldName ?? "unknown"
2184
2191
  });
2185
2192
  }
2186
2193
  this.issues.push({
@@ -2216,7 +2223,7 @@ class ConfigValidator {
2216
2223
  loadConfig(configPath) {
2217
2224
  delete __require.cache[__require.resolve(path.resolve(configPath))];
2218
2225
  const module = __require(path.resolve(configPath));
2219
- return module.default || module;
2226
+ return module.verificationConfig || module.default || module;
2220
2227
  }
2221
2228
  validateConfig(config) {
2222
2229
  this.findNullPlaceholders(config.state, "state");
@@ -2273,7 +2280,7 @@ class ConfigValidator {
2273
2280
  });
2274
2281
  }
2275
2282
  }
2276
- if (config.messages.maxTabs !== null) {
2283
+ if (config.messages.maxTabs !== null && config.messages.maxTabs !== undefined) {
2277
2284
  if (config.messages.maxTabs < 1) {
2278
2285
  this.issues.push({
2279
2286
  type: "invalid_value",
@@ -2374,7 +2381,7 @@ function validateConfig(configPath) {
2374
2381
  }
2375
2382
 
2376
2383
  // vendor/verify/src/cli.ts
2377
- var __dirname = "/Users/AJT/projects/polly/packages/polly/vendor/verify/src";
2384
+ var __dirname = "/Users/AJT/projects/polly/vendor/verify/src";
2378
2385
  var COLORS = {
2379
2386
  reset: "\x1B[0m",
2380
2387
  red: "\x1B[31m",
@@ -2448,7 +2455,7 @@ async function setupCommand() {
2448
2455
  table.push([field.path, field.type.kind, status]);
2449
2456
  }
2450
2457
  for (const row of table) {
2451
- console.log(` ${row[0].padEnd(32)} ${row[1].padEnd(22)} ${row[2]}`);
2458
+ console.log(` ${row[0]?.padEnd(32) ?? ""} ${row[1]?.padEnd(22) ?? ""} ${row[2] ?? ""}`);
2452
2459
  }
2453
2460
  }
2454
2461
  const configContent = generateConfig(analysis);
@@ -2565,9 +2572,9 @@ async function verifyCommand() {
2565
2572
  async function runFullVerification(configPath) {
2566
2573
  const { generateTLA: generateTLA2 } = await Promise.resolve().then(() => exports_tla);
2567
2574
  const { DockerRunner: DockerRunner2 } = await Promise.resolve().then(() => (init_docker(), exports_docker));
2568
- delete __require.cache[__require.resolve(path3.resolve(configPath))];
2569
- const configModule = __require(path3.resolve(configPath));
2570
- const config = configModule.default || configModule;
2575
+ const resolvedPath = path3.resolve(configPath);
2576
+ const configModule = await import(`file://${resolvedPath}?t=${Date.now()}`);
2577
+ const config = configModule.default;
2571
2578
  console.log(color("\uD83D\uDCCA Analyzing codebase...", COLORS.blue));
2572
2579
  const tsConfigPath = findTsConfig();
2573
2580
  if (!tsConfigPath) {
@@ -2743,4 +2750,4 @@ Stack trace:`, COLORS.gray));
2743
2750
  process.exit(1);
2744
2751
  });
2745
2752
 
2746
- //# debugId=C40ED4F55177D0FC64756E2164756E21
2753
+ //# debugId=C7C70A8E076468AA64756E2164756E21