saasfunnels 0.3.3 → 0.3.4

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.
@@ -43,7 +43,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
43
43
  // node_modules/typescript/lib/typescript.js
44
44
  var require_typescript = __commonJS({
45
45
  "node_modules/typescript/lib/typescript.js"(exports, module) {
46
- var ts2 = {};
46
+ var ts6 = {};
47
47
  ((module2) => {
48
48
  "use strict";
49
49
  var __defProp2 = Object.defineProperty;
@@ -8649,7 +8649,7 @@ ${lanes.join("\n")}
8649
8649
  writeOutputIsTTY() {
8650
8650
  return process.stdout.isTTY;
8651
8651
  },
8652
- readFile: readFile7,
8652
+ readFile: readFile8,
8653
8653
  writeFile: writeFile22,
8654
8654
  watchFile: watchFile2,
8655
8655
  watchDirectory,
@@ -8855,7 +8855,7 @@ ${lanes.join("\n")}
8855
8855
  callback
8856
8856
  );
8857
8857
  }
8858
- function readFile7(fileName, _encoding) {
8858
+ function readFile8(fileName, _encoding) {
8859
8859
  let buffer;
8860
8860
  try {
8861
8861
  buffer = _fs.readFileSync(fileName);
@@ -30472,10 +30472,10 @@ ${lanes.join("\n")}
30472
30472
  return expressions.length > 10 ? createCommaListExpression(expressions) : reduceLeft(expressions, factory2.createComma);
30473
30473
  }
30474
30474
  function getName(node, allowComments, allowSourceMaps, emitFlags = 0, ignoreAssignedName) {
30475
- const nodeName = ignoreAssignedName ? node && getNonAssignedNameOfDeclaration(node) : getNameOfDeclaration(node);
30476
- if (nodeName && isIdentifier(nodeName) && !isGeneratedIdentifier(nodeName)) {
30477
- const name = setParent(setTextRange(cloneNode(nodeName), nodeName), nodeName.parent);
30478
- emitFlags |= getEmitFlags(nodeName);
30475
+ const nodeName2 = ignoreAssignedName ? node && getNonAssignedNameOfDeclaration(node) : getNameOfDeclaration(node);
30476
+ if (nodeName2 && isIdentifier(nodeName2) && !isGeneratedIdentifier(nodeName2)) {
30477
+ const name = setParent(setTextRange(cloneNode(nodeName2), nodeName2), nodeName2.parent);
30478
+ emitFlags |= getEmitFlags(nodeName2);
30479
30479
  if (!allowSourceMaps) emitFlags |= 96;
30480
30480
  if (!allowComments) emitFlags |= 3072;
30481
30481
  if (emitFlags) setEmitFlags(name, emitFlags);
@@ -30936,7 +30936,7 @@ ${lanes.join("\n")}
30936
30936
  startsOnNewLine,
30937
30937
  snippetElement,
30938
30938
  classThis,
30939
- assignedName: assignedName2
30939
+ assignedName
30940
30940
  } = sourceEmitNode;
30941
30941
  if (!destEmitNode) destEmitNode = {};
30942
30942
  if (flags) {
@@ -30977,8 +30977,8 @@ ${lanes.join("\n")}
30977
30977
  if (classThis) {
30978
30978
  destEmitNode.classThis = classThis;
30979
30979
  }
30980
- if (assignedName2) {
30981
- destEmitNode.assignedName = assignedName2;
30980
+ if (assignedName) {
30981
+ destEmitNode.assignedName = assignedName;
30982
30982
  }
30983
30983
  return destEmitNode;
30984
30984
  }
@@ -45538,7 +45538,7 @@ ${lanes.join("\n")}
45538
45538
  const possibleOption = getSpellingSuggestion(unknownOption, diagnostics.optionDeclarations, getOptionName);
45539
45539
  return possibleOption ? createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, node, diagnostics.unknownDidYouMeanDiagnostic, unknownOptionErrorText || unknownOption, possibleOption.name) : createDiagnosticForNodeInSourceFileOrCompilerDiagnostic(sourceFile, node, diagnostics.unknownOptionDiagnostic, unknownOptionErrorText || unknownOption);
45540
45540
  }
45541
- function parseCommandLineWorker(diagnostics, commandLine, readFile7) {
45541
+ function parseCommandLineWorker(diagnostics, commandLine, readFile8) {
45542
45542
  const options = {};
45543
45543
  let watchOptions;
45544
45544
  const fileNames = [];
@@ -45586,7 +45586,7 @@ ${lanes.join("\n")}
45586
45586
  }
45587
45587
  }
45588
45588
  function parseResponseFile(fileName) {
45589
- const text = tryReadFile(fileName, readFile7 || ((fileName2) => sys.readFile(fileName2)));
45589
+ const text = tryReadFile(fileName, readFile8 || ((fileName2) => sys.readFile(fileName2)));
45590
45590
  if (!isString(text)) {
45591
45591
  errors.push(text);
45592
45592
  return;
@@ -45689,8 +45689,8 @@ ${lanes.join("\n")}
45689
45689
  unknownDidYouMeanDiagnostic: Diagnostics.Unknown_compiler_option_0_Did_you_mean_1,
45690
45690
  optionTypeMismatchDiagnostic: Diagnostics.Compiler_option_0_expects_an_argument
45691
45691
  };
45692
- function parseCommandLine(commandLine, readFile7) {
45693
- return parseCommandLineWorker(compilerOptionsDidYouMeanDiagnostics, commandLine, readFile7);
45692
+ function parseCommandLine(commandLine, readFile8) {
45693
+ return parseCommandLineWorker(compilerOptionsDidYouMeanDiagnostics, commandLine, readFile8);
45694
45694
  }
45695
45695
  function getOptionFromName(optionName, allowShort) {
45696
45696
  return getOptionDeclarationFromName(getOptionsNameMap, optionName, allowShort);
@@ -45772,8 +45772,8 @@ ${lanes.join("\n")}
45772
45772
  watchOptionsToExtend
45773
45773
  );
45774
45774
  }
45775
- function readConfigFile(fileName, readFile7) {
45776
- const textOrDiagnostic = tryReadFile(fileName, readFile7);
45775
+ function readConfigFile(fileName, readFile8) {
45776
+ const textOrDiagnostic = tryReadFile(fileName, readFile8);
45777
45777
  return isString(textOrDiagnostic) ? parseConfigFileTextToJson(fileName, textOrDiagnostic) : { config: {}, error: textOrDiagnostic };
45778
45778
  }
45779
45779
  function parseConfigFileTextToJson(fileName, jsonText) {
@@ -45788,14 +45788,14 @@ ${lanes.join("\n")}
45788
45788
  error: jsonSourceFile.parseDiagnostics.length ? jsonSourceFile.parseDiagnostics[0] : void 0
45789
45789
  };
45790
45790
  }
45791
- function readJsonConfigFile(fileName, readFile7) {
45792
- const textOrDiagnostic = tryReadFile(fileName, readFile7);
45791
+ function readJsonConfigFile(fileName, readFile8) {
45792
+ const textOrDiagnostic = tryReadFile(fileName, readFile8);
45793
45793
  return isString(textOrDiagnostic) ? parseJsonText(fileName, textOrDiagnostic) : { fileName, parseDiagnostics: [textOrDiagnostic] };
45794
45794
  }
45795
- function tryReadFile(fileName, readFile7) {
45795
+ function tryReadFile(fileName, readFile8) {
45796
45796
  let text;
45797
45797
  try {
45798
- text = readFile7(fileName);
45798
+ text = readFile8(fileName);
45799
45799
  } catch (e) {
45800
45800
  return createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, e.message);
45801
45801
  }
@@ -62210,10 +62210,10 @@ ${lanes.join("\n")}
62210
62210
  }
62211
62211
  let expression;
62212
62212
  if (isSingleOrDoubleQuote(firstChar) && !(symbol22.flags & 8)) {
62213
- const literalText = stripQuotes(symbolName2).replace(/\\./g, (s) => s.substring(1));
62214
- context.approximateLength += literalText.length + 2;
62213
+ const literalText2 = stripQuotes(symbolName2).replace(/\\./g, (s) => s.substring(1));
62214
+ context.approximateLength += literalText2.length + 2;
62215
62215
  expression = factory.createStringLiteral(
62216
- literalText,
62216
+ literalText2,
62217
62217
  firstChar === 39
62218
62218
  /* singleQuote */
62219
62219
  );
@@ -105852,27 +105852,27 @@ ${lanes.join("\n")}
105852
105852
  function getAssignedNameOfPropertyName(context, name, assignedNameText) {
105853
105853
  const { factory: factory2 } = context;
105854
105854
  if (assignedNameText !== void 0) {
105855
- const assignedName22 = factory2.createStringLiteral(assignedNameText);
105856
- return { assignedName: assignedName22, name };
105855
+ const assignedName2 = factory2.createStringLiteral(assignedNameText);
105856
+ return { assignedName: assignedName2, name };
105857
105857
  }
105858
105858
  if (isPropertyNameLiteral(name) || isPrivateIdentifier(name)) {
105859
- const assignedName22 = factory2.createStringLiteralFromNode(name);
105860
- return { assignedName: assignedName22, name };
105859
+ const assignedName2 = factory2.createStringLiteralFromNode(name);
105860
+ return { assignedName: assignedName2, name };
105861
105861
  }
105862
105862
  if (isPropertyNameLiteral(name.expression) && !isIdentifier(name.expression)) {
105863
- const assignedName22 = factory2.createStringLiteralFromNode(name.expression);
105864
- return { assignedName: assignedName22, name };
105863
+ const assignedName2 = factory2.createStringLiteralFromNode(name.expression);
105864
+ return { assignedName: assignedName2, name };
105865
105865
  }
105866
- const assignedName2 = factory2.getGeneratedNameForNode(name);
105867
- context.hoistVariableDeclaration(assignedName2);
105866
+ const assignedName = factory2.getGeneratedNameForNode(name);
105867
+ context.hoistVariableDeclaration(assignedName);
105868
105868
  const key2 = context.getEmitHelperFactory().createPropKeyHelper(name.expression);
105869
- const assignment = factory2.createAssignment(assignedName2, key2);
105869
+ const assignment = factory2.createAssignment(assignedName, key2);
105870
105870
  const updatedName = factory2.updateComputedPropertyName(name, assignment);
105871
- return { assignedName: assignedName2, name: updatedName };
105871
+ return { assignedName, name: updatedName };
105872
105872
  }
105873
- function createClassNamedEvaluationHelperBlock(context, assignedName2, thisExpression = context.factory.createThis()) {
105873
+ function createClassNamedEvaluationHelperBlock(context, assignedName, thisExpression = context.factory.createThis()) {
105874
105874
  const { factory: factory2 } = context;
105875
- const expression = context.getEmitHelperFactory().createSetFunctionNameHelper(thisExpression, assignedName2);
105875
+ const expression = context.getEmitHelperFactory().createSetFunctionNameHelper(thisExpression, assignedName);
105876
105876
  const statement = factory2.createExpressionStatement(expression);
105877
105877
  const body = factory2.createBlock(
105878
105878
  [statement],
@@ -105880,7 +105880,7 @@ ${lanes.join("\n")}
105880
105880
  false
105881
105881
  );
105882
105882
  const block = factory2.createClassStaticBlockDeclaration(body);
105883
- getOrCreateEmitNode(block).assignedName = assignedName2;
105883
+ getOrCreateEmitNode(block).assignedName = assignedName;
105884
105884
  return block;
105885
105885
  }
105886
105886
  function isClassNamedEvaluationHelperBlock(node) {
@@ -105898,12 +105898,12 @@ ${lanes.join("\n")}
105898
105898
  function classHasDeclaredOrExplicitlyAssignedName(node) {
105899
105899
  return !!node.name || classHasExplicitlyAssignedName(node);
105900
105900
  }
105901
- function injectClassNamedEvaluationHelperBlockIfMissing(context, node, assignedName2, thisExpression) {
105901
+ function injectClassNamedEvaluationHelperBlockIfMissing(context, node, assignedName, thisExpression) {
105902
105902
  if (classHasExplicitlyAssignedName(node)) {
105903
105903
  return node;
105904
105904
  }
105905
105905
  const { factory: factory2 } = context;
105906
- const namedEvaluationBlock = createClassNamedEvaluationHelperBlock(context, assignedName2, thisExpression);
105906
+ const namedEvaluationBlock = createClassNamedEvaluationHelperBlock(context, assignedName, thisExpression);
105907
105907
  if (node.name) {
105908
105908
  setSourceMapRange(namedEvaluationBlock.body.statements[0], node.name);
105909
105909
  }
@@ -105927,22 +105927,22 @@ ${lanes.join("\n")}
105927
105927
  node.heritageClauses,
105928
105928
  members
105929
105929
  );
105930
- getOrCreateEmitNode(node).assignedName = assignedName2;
105930
+ getOrCreateEmitNode(node).assignedName = assignedName;
105931
105931
  return node;
105932
105932
  }
105933
- function finishTransformNamedEvaluation(context, expression, assignedName2, ignoreEmptyStringLiteral) {
105934
- if (ignoreEmptyStringLiteral && isStringLiteral(assignedName2) && isEmptyStringLiteral(assignedName2)) {
105933
+ function finishTransformNamedEvaluation(context, expression, assignedName, ignoreEmptyStringLiteral) {
105934
+ if (ignoreEmptyStringLiteral && isStringLiteral(assignedName) && isEmptyStringLiteral(assignedName)) {
105935
105935
  return expression;
105936
105936
  }
105937
105937
  const { factory: factory2 } = context;
105938
105938
  const innerExpression = skipOuterExpressions(expression);
105939
- const updatedExpression = isClassExpression(innerExpression) ? cast(injectClassNamedEvaluationHelperBlockIfMissing(context, innerExpression, assignedName2), isClassExpression) : context.getEmitHelperFactory().createSetFunctionNameHelper(innerExpression, assignedName2);
105939
+ const updatedExpression = isClassExpression(innerExpression) ? cast(injectClassNamedEvaluationHelperBlockIfMissing(context, innerExpression, assignedName), isClassExpression) : context.getEmitHelperFactory().createSetFunctionNameHelper(innerExpression, assignedName);
105940
105940
  return factory2.restoreOuterExpressions(expression, updatedExpression);
105941
105941
  }
105942
105942
  function transformNamedEvaluationOfPropertyAssignment(context, node, ignoreEmptyStringLiteral, assignedNameText) {
105943
105943
  const { factory: factory2 } = context;
105944
- const { assignedName: assignedName2, name } = getAssignedNameOfPropertyName(context, node.name, assignedNameText);
105945
- const initializer3 = finishTransformNamedEvaluation(context, node.initializer, assignedName2, ignoreEmptyStringLiteral);
105944
+ const { assignedName, name } = getAssignedNameOfPropertyName(context, node.name, assignedNameText);
105945
+ const initializer3 = finishTransformNamedEvaluation(context, node.initializer, assignedName, ignoreEmptyStringLiteral);
105946
105946
  return factory2.updatePropertyAssignment(
105947
105947
  node,
105948
105948
  name,
@@ -105951,8 +105951,8 @@ ${lanes.join("\n")}
105951
105951
  }
105952
105952
  function transformNamedEvaluationOfShorthandAssignmentProperty(context, node, ignoreEmptyStringLiteral, assignedNameText) {
105953
105953
  const { factory: factory2 } = context;
105954
- const assignedName2 = assignedNameText !== void 0 ? factory2.createStringLiteral(assignedNameText) : getAssignedNameOfIdentifier(factory2, node.name, node.objectAssignmentInitializer);
105955
- const objectAssignmentInitializer = finishTransformNamedEvaluation(context, node.objectAssignmentInitializer, assignedName2, ignoreEmptyStringLiteral);
105954
+ const assignedName = assignedNameText !== void 0 ? factory2.createStringLiteral(assignedNameText) : getAssignedNameOfIdentifier(factory2, node.name, node.objectAssignmentInitializer);
105955
+ const objectAssignmentInitializer = finishTransformNamedEvaluation(context, node.objectAssignmentInitializer, assignedName, ignoreEmptyStringLiteral);
105956
105956
  return factory2.updateShorthandPropertyAssignment(
105957
105957
  node,
105958
105958
  node.name,
@@ -105961,8 +105961,8 @@ ${lanes.join("\n")}
105961
105961
  }
105962
105962
  function transformNamedEvaluationOfVariableDeclaration(context, node, ignoreEmptyStringLiteral, assignedNameText) {
105963
105963
  const { factory: factory2 } = context;
105964
- const assignedName2 = assignedNameText !== void 0 ? factory2.createStringLiteral(assignedNameText) : getAssignedNameOfIdentifier(factory2, node.name, node.initializer);
105965
- const initializer3 = finishTransformNamedEvaluation(context, node.initializer, assignedName2, ignoreEmptyStringLiteral);
105964
+ const assignedName = assignedNameText !== void 0 ? factory2.createStringLiteral(assignedNameText) : getAssignedNameOfIdentifier(factory2, node.name, node.initializer);
105965
+ const initializer3 = finishTransformNamedEvaluation(context, node.initializer, assignedName, ignoreEmptyStringLiteral);
105966
105966
  return factory2.updateVariableDeclaration(
105967
105967
  node,
105968
105968
  node.name,
@@ -105973,8 +105973,8 @@ ${lanes.join("\n")}
105973
105973
  }
105974
105974
  function transformNamedEvaluationOfParameterDeclaration(context, node, ignoreEmptyStringLiteral, assignedNameText) {
105975
105975
  const { factory: factory2 } = context;
105976
- const assignedName2 = assignedNameText !== void 0 ? factory2.createStringLiteral(assignedNameText) : getAssignedNameOfIdentifier(factory2, node.name, node.initializer);
105977
- const initializer3 = finishTransformNamedEvaluation(context, node.initializer, assignedName2, ignoreEmptyStringLiteral);
105976
+ const assignedName = assignedNameText !== void 0 ? factory2.createStringLiteral(assignedNameText) : getAssignedNameOfIdentifier(factory2, node.name, node.initializer);
105977
+ const initializer3 = finishTransformNamedEvaluation(context, node.initializer, assignedName, ignoreEmptyStringLiteral);
105978
105978
  return factory2.updateParameterDeclaration(
105979
105979
  node,
105980
105980
  node.modifiers,
@@ -105987,8 +105987,8 @@ ${lanes.join("\n")}
105987
105987
  }
105988
105988
  function transformNamedEvaluationOfBindingElement(context, node, ignoreEmptyStringLiteral, assignedNameText) {
105989
105989
  const { factory: factory2 } = context;
105990
- const assignedName2 = assignedNameText !== void 0 ? factory2.createStringLiteral(assignedNameText) : getAssignedNameOfIdentifier(factory2, node.name, node.initializer);
105991
- const initializer3 = finishTransformNamedEvaluation(context, node.initializer, assignedName2, ignoreEmptyStringLiteral);
105990
+ const assignedName = assignedNameText !== void 0 ? factory2.createStringLiteral(assignedNameText) : getAssignedNameOfIdentifier(factory2, node.name, node.initializer);
105991
+ const initializer3 = finishTransformNamedEvaluation(context, node.initializer, assignedName, ignoreEmptyStringLiteral);
105992
105992
  return factory2.updateBindingElement(
105993
105993
  node,
105994
105994
  node.dotDotDotToken,
@@ -105999,8 +105999,8 @@ ${lanes.join("\n")}
105999
105999
  }
106000
106000
  function transformNamedEvaluationOfPropertyDeclaration(context, node, ignoreEmptyStringLiteral, assignedNameText) {
106001
106001
  const { factory: factory2 } = context;
106002
- const { assignedName: assignedName2, name } = getAssignedNameOfPropertyName(context, node.name, assignedNameText);
106003
- const initializer3 = finishTransformNamedEvaluation(context, node.initializer, assignedName2, ignoreEmptyStringLiteral);
106002
+ const { assignedName, name } = getAssignedNameOfPropertyName(context, node.name, assignedNameText);
106003
+ const initializer3 = finishTransformNamedEvaluation(context, node.initializer, assignedName, ignoreEmptyStringLiteral);
106004
106004
  return factory2.updatePropertyDeclaration(
106005
106005
  node,
106006
106006
  node.modifiers,
@@ -106012,8 +106012,8 @@ ${lanes.join("\n")}
106012
106012
  }
106013
106013
  function transformNamedEvaluationOfAssignmentExpression(context, node, ignoreEmptyStringLiteral, assignedNameText) {
106014
106014
  const { factory: factory2 } = context;
106015
- const assignedName2 = assignedNameText !== void 0 ? factory2.createStringLiteral(assignedNameText) : getAssignedNameOfIdentifier(factory2, node.left, node.right);
106016
- const right = finishTransformNamedEvaluation(context, node.right, assignedName2, ignoreEmptyStringLiteral);
106015
+ const assignedName = assignedNameText !== void 0 ? factory2.createStringLiteral(assignedNameText) : getAssignedNameOfIdentifier(factory2, node.left, node.right);
106016
+ const right = finishTransformNamedEvaluation(context, node.right, assignedName, ignoreEmptyStringLiteral);
106017
106017
  return factory2.updateBinaryExpression(
106018
106018
  node,
106019
106019
  node.left,
@@ -106023,32 +106023,32 @@ ${lanes.join("\n")}
106023
106023
  }
106024
106024
  function transformNamedEvaluationOfExportAssignment(context, node, ignoreEmptyStringLiteral, assignedNameText) {
106025
106025
  const { factory: factory2 } = context;
106026
- const assignedName2 = assignedNameText !== void 0 ? factory2.createStringLiteral(assignedNameText) : factory2.createStringLiteral(node.isExportEquals ? "" : "default");
106027
- const expression = finishTransformNamedEvaluation(context, node.expression, assignedName2, ignoreEmptyStringLiteral);
106026
+ const assignedName = assignedNameText !== void 0 ? factory2.createStringLiteral(assignedNameText) : factory2.createStringLiteral(node.isExportEquals ? "" : "default");
106027
+ const expression = finishTransformNamedEvaluation(context, node.expression, assignedName, ignoreEmptyStringLiteral);
106028
106028
  return factory2.updateExportAssignment(
106029
106029
  node,
106030
106030
  node.modifiers,
106031
106031
  expression
106032
106032
  );
106033
106033
  }
106034
- function transformNamedEvaluation(context, node, ignoreEmptyStringLiteral, assignedName2) {
106034
+ function transformNamedEvaluation(context, node, ignoreEmptyStringLiteral, assignedName) {
106035
106035
  switch (node.kind) {
106036
106036
  case 304:
106037
- return transformNamedEvaluationOfPropertyAssignment(context, node, ignoreEmptyStringLiteral, assignedName2);
106037
+ return transformNamedEvaluationOfPropertyAssignment(context, node, ignoreEmptyStringLiteral, assignedName);
106038
106038
  case 305:
106039
- return transformNamedEvaluationOfShorthandAssignmentProperty(context, node, ignoreEmptyStringLiteral, assignedName2);
106039
+ return transformNamedEvaluationOfShorthandAssignmentProperty(context, node, ignoreEmptyStringLiteral, assignedName);
106040
106040
  case 261:
106041
- return transformNamedEvaluationOfVariableDeclaration(context, node, ignoreEmptyStringLiteral, assignedName2);
106041
+ return transformNamedEvaluationOfVariableDeclaration(context, node, ignoreEmptyStringLiteral, assignedName);
106042
106042
  case 170:
106043
- return transformNamedEvaluationOfParameterDeclaration(context, node, ignoreEmptyStringLiteral, assignedName2);
106043
+ return transformNamedEvaluationOfParameterDeclaration(context, node, ignoreEmptyStringLiteral, assignedName);
106044
106044
  case 209:
106045
- return transformNamedEvaluationOfBindingElement(context, node, ignoreEmptyStringLiteral, assignedName2);
106045
+ return transformNamedEvaluationOfBindingElement(context, node, ignoreEmptyStringLiteral, assignedName);
106046
106046
  case 173:
106047
- return transformNamedEvaluationOfPropertyDeclaration(context, node, ignoreEmptyStringLiteral, assignedName2);
106047
+ return transformNamedEvaluationOfPropertyDeclaration(context, node, ignoreEmptyStringLiteral, assignedName);
106048
106048
  case 227:
106049
- return transformNamedEvaluationOfAssignmentExpression(context, node, ignoreEmptyStringLiteral, assignedName2);
106049
+ return transformNamedEvaluationOfAssignmentExpression(context, node, ignoreEmptyStringLiteral, assignedName);
106050
106050
  case 278:
106051
- return transformNamedEvaluationOfExportAssignment(context, node, ignoreEmptyStringLiteral, assignedName2);
106051
+ return transformNamedEvaluationOfExportAssignment(context, node, ignoreEmptyStringLiteral, assignedName);
106052
106052
  }
106053
106053
  }
106054
106054
  var ProcessLevel = /* @__PURE__ */ ((ProcessLevel2) => {
@@ -135899,12 +135899,12 @@ ${lanes.join("\n")}
135899
135899
  function createCompilerHost(options, setParentNodes) {
135900
135900
  return createCompilerHostWorker(options, setParentNodes);
135901
135901
  }
135902
- function createGetSourceFile(readFile7, setParentNodes) {
135902
+ function createGetSourceFile(readFile8, setParentNodes) {
135903
135903
  return (fileName, languageVersionOrOptions, onError) => {
135904
135904
  let text;
135905
135905
  try {
135906
135906
  mark("beforeIORead");
135907
- text = readFile7(fileName);
135907
+ text = readFile8(fileName);
135908
135908
  mark("afterIORead");
135909
135909
  measure("I/O Read", "beforeIORead", "afterIORead");
135910
135910
  } catch (e) {
@@ -136808,7 +136808,7 @@ ${lanes.join("\n")}
136808
136808
  getRedirectFromOutput,
136809
136809
  forEachResolvedProjectReference: forEachResolvedProjectReference2
136810
136810
  });
136811
- const readFile7 = host.readFile.bind(host);
136811
+ const readFile8 = host.readFile.bind(host);
136812
136812
  (_e = tracing) == null ? void 0 : _e.push(tracing.Phase.Program, "shouldProgramCreateNewSourceFiles", { hasOldProgram: !!oldProgram });
136813
136813
  const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options);
136814
136814
  (_f = tracing) == null ? void 0 : _f.pop();
@@ -137029,7 +137029,7 @@ ${lanes.join("\n")}
137029
137029
  shouldTransformImportCall,
137030
137030
  emitBuildInfo,
137031
137031
  fileExists,
137032
- readFile: readFile7,
137032
+ readFile: readFile8,
137033
137033
  directoryExists,
137034
137034
  getSymlinkCache,
137035
137035
  realpath: (_o = host.realpath) == null ? void 0 : _o.bind(host),
@@ -211562,9 +211562,9 @@ Additional information: BADCLIENT: Bad error code, ${badCode} not found in range
211562
211562
  };
211563
211563
  }
211564
211564
  })({ get exports() {
211565
- return ts2;
211565
+ return ts6;
211566
211566
  }, set exports(v) {
211567
- ts2 = v;
211567
+ ts6 = v;
211568
211568
  if (typeof module !== "undefined" && module.exports) {
211569
211569
  module.exports = v;
211570
211570
  }
@@ -216136,9 +216136,9 @@ var require_resolve_block_scalar = __commonJS({
216136
216136
  default: {
216137
216137
  const message = `Unexpected token in block scalar header: ${token.type}`;
216138
216138
  onError(token, "UNEXPECTED_TOKEN", message);
216139
- const ts2 = token.source;
216140
- if (ts2 && typeof ts2 === "string")
216141
- length += ts2.length;
216139
+ const ts6 = token.source;
216140
+ if (ts6 && typeof ts6 === "string")
216141
+ length += ts6.length;
216142
216142
  }
216143
216143
  }
216144
216144
  }
@@ -216447,9 +216447,9 @@ var require_compose_scalar = __commonJS({
216447
216447
  if (schema.compat) {
216448
216448
  const compat = schema.compat.find((tag2) => tag2.default && tag2.test?.test(value)) ?? schema[identity.SCALAR];
216449
216449
  if (tag.tag !== compat.tag) {
216450
- const ts2 = directives.tagString(tag.tag);
216450
+ const ts6 = directives.tagString(tag.tag);
216451
216451
  const cs = directives.tagString(compat.tag);
216452
- const msg = `Value may be parsed as either ${ts2} or ${cs}`;
216452
+ const msg = `Value may be parsed as either ${ts6} or ${cs}`;
216453
216453
  onError(token, "TAG_RESOLVE_FAILED", msg, true);
216454
216454
  }
216455
216455
  }
@@ -218943,10 +218943,178 @@ async function resolveSetupAccess(options) {
218943
218943
  }
218944
218944
 
218945
218945
  // src/cli.ts
218946
- import { dirname as dirname3, join as join5, resolve as resolve5 } from "node:path";
218946
+ import { dirname as dirname3, join as join6, resolve as resolve5 } from "node:path";
218947
218947
 
218948
- // src/setup-pricing.ts
218948
+ // src/source-analysis.ts
218949
218949
  var import_typescript = __toESM(require_typescript(), 1);
218950
+ var nonProductName = /(?:^|[_-])(?:test|tests|fixture|fixtures|mock|mocks|demo|sample|e2e|storybook)(?:$|[_-])|(?:^|[a-z])(?:TestFixture|Fixture|Mock|Demo|E2e|E2E|Storybook)(?:[A-Z]|$)|^(?:test|mock|demo|fixture|sample|e2e)[A-Z]/;
218951
+ var nonProductPath = /(?:^|\/)(?:__tests__|__mocks__|tests?|fixtures?|mocks?|stories|examples?|qa)(?:\/|$)|(?:^|[\/._-])(?:fixture|fixtures|e2e|mock|stories)(?:[._-]|$)|\.(?:test|spec|stories|d)\.[cm]?[jt]sx?$/i;
218952
+ function parseApplicationSource(path, source) {
218953
+ return import_typescript.default.createSourceFile(
218954
+ path,
218955
+ source,
218956
+ import_typescript.default.ScriptTarget.Latest,
218957
+ true,
218958
+ /\.[jt]sx$/.test(path) ? import_typescript.default.ScriptKind.TSX : import_typescript.default.ScriptKind.TS
218959
+ );
218960
+ }
218961
+ function nodeName(node) {
218962
+ if ((import_typescript.default.isFunctionDeclaration(node) || import_typescript.default.isClassDeclaration(node) || import_typescript.default.isMethodDeclaration(node) || import_typescript.default.isVariableDeclaration(node)) && node.name)
218963
+ return node.name.getText();
218964
+ return null;
218965
+ }
218966
+ function demoCondition(expression) {
218967
+ if (import_typescript.default.isParenthesizedExpression(expression))
218968
+ return demoCondition(expression.expression);
218969
+ if (import_typescript.default.isPrefixUnaryExpression(expression) && expression.operator === import_typescript.default.SyntaxKind.ExclamationToken) {
218970
+ const value = demoCondition(expression.operand);
218971
+ return value === null ? null : !value;
218972
+ }
218973
+ const text = expression.getText();
218974
+ if (/^(?:isDemo|demoMode|isTest|[A-Z_]*(?:E2E|FIXTURES|MOCKS)[A-Z_]*)$/.test(
218975
+ text
218976
+ ) || /^(?:process\.env|import\.meta\.env)\.[A-Z_]*(?:E2E|FIXTURES|MOCKS)[A-Z_]*$/.test(
218977
+ text
218978
+ ))
218979
+ return true;
218980
+ if (import_typescript.default.isBinaryExpression(expression)) {
218981
+ const op = expression.operatorToken.kind;
218982
+ const equality = [
218983
+ import_typescript.default.SyntaxKind.EqualsEqualsToken,
218984
+ import_typescript.default.SyntaxKind.EqualsEqualsEqualsToken
218985
+ ].includes(op);
218986
+ const inequality = [
218987
+ import_typescript.default.SyntaxKind.ExclamationEqualsToken,
218988
+ import_typescript.default.SyntaxKind.ExclamationEqualsEqualsToken
218989
+ ].includes(op);
218990
+ if (!equality && !inequality) return null;
218991
+ const right = expression.right;
218992
+ const value = import_typescript.default.isStringLiteral(right) ? right.text : right.kind === import_typescript.default.SyntaxKind.TrueKeyword ? "1" : right.kind === import_typescript.default.SyntaxKind.FalseKeyword ? "0" : null;
218993
+ const nodeEnv = /(?:^|\.)NODE_ENV$/.test(expression.left.getText());
218994
+ const positive = nodeEnv && value === "test" ? true : demoCondition(expression.left);
218995
+ if (positive === null || nodeEnv && value !== "test") return null;
218996
+ const enabled = nodeEnv || value === "1" || value === "true";
218997
+ if (!enabled && value !== "0" && value !== "false") return null;
218998
+ return equality ? enabled === positive : enabled !== positive;
218999
+ }
219000
+ return null;
219001
+ }
219002
+ function isProductNode(node) {
219003
+ for (let current = node; current; current = current.parent) {
219004
+ const name = nodeName(current);
219005
+ if (name && nonProductName.test(name)) return false;
219006
+ if (import_typescript.default.isIfStatement(current) || import_typescript.default.isConditionalExpression(current)) {
219007
+ const value = demoCondition(
219008
+ import_typescript.default.isIfStatement(current) ? current.expression : current.condition
219009
+ );
219010
+ if (value === null) continue;
219011
+ let child = node;
219012
+ while (child.parent && child.parent !== current) child = child.parent;
219013
+ const excluded = import_typescript.default.isIfStatement(current) ? value ? current.thenStatement : current.elseStatement : value ? current.whenTrue : current.whenFalse;
219014
+ if (child === excluded) return false;
219015
+ }
219016
+ }
219017
+ return true;
219018
+ }
219019
+ function enclosingSymbol(node) {
219020
+ for (let current = node; current; current = current.parent) {
219021
+ const name = nodeName(current);
219022
+ if (name) return name.slice(0, 120);
219023
+ }
219024
+ return "module";
219025
+ }
219026
+ function literalText(node) {
219027
+ return node && (import_typescript.default.isStringLiteral(node) || import_typescript.default.isNoSubstitutionTemplateLiteral(node)) ? node.text : null;
219028
+ }
219029
+ function namedFeatureEvidence(path, source) {
219030
+ if (nonProductPath.test(path)) return [];
219031
+ const file2 = parseApplicationSource(path, source);
219032
+ const findings = [];
219033
+ const add = (node, key2, model, kind, reason) => {
219034
+ if (!key2 || !/^[a-z][a-z0-9_.-]{0,79}$/.test(key2)) return;
219035
+ findings.push({
219036
+ key: key2,
219037
+ model,
219038
+ kind,
219039
+ reason,
219040
+ line: file2.getLineAndCharacterOfPosition(node.getStart(file2)).line + 1,
219041
+ symbol: enclosingSymbol(node)
219042
+ });
219043
+ };
219044
+ const visit = (node) => {
219045
+ if (!isProductNode(node)) return;
219046
+ if (import_typescript.default.isCallExpression(node)) {
219047
+ const name = import_typescript.default.isIdentifier(node.expression) ? node.expression.text : import_typescript.default.isPropertyAccessExpression(node.expression) ? node.expression.name.text : "";
219048
+ const featureCall = /^(?:has|check|require|assert|canUse|enforce|authorize|evaluate|is).*?(?:Feature|Entitlement)(?:Enabled|Access)?$/i.test(
219049
+ name
219050
+ ) || /^(?:has|check|require|assert|canUse|enforce|authorize|evaluate|is).*Capability(?:Enabled|Access)?$/i.test(
219051
+ name
219052
+ ) && /billing|plan|subscription|commercial|product/i.test(name);
219053
+ const limitCall = /^(?:check|require|assert|enforce|report|track|consume).*?(?:Quota|Usage|Limit)$/i.test(
219054
+ name
219055
+ );
219056
+ if (featureCall || limitCall) {
219057
+ const literals = node.arguments.map(literalText).filter((v) => v !== null);
219058
+ let key2 = literals.length === 1 ? literals[0] : null;
219059
+ for (const arg of node.arguments)
219060
+ if (import_typescript.default.isObjectLiteralExpression(arg)) {
219061
+ for (const p of arg.properties)
219062
+ if (import_typescript.default.isPropertyAssignment(p) && /^(featureKey|feature|capability|entitlement|quotaKey|limitKey|meterKey)$/.test(
219063
+ p.name.getText(file2).replace(/["']/g, "")
219064
+ ))
219065
+ key2 = literalText(p.initializer);
219066
+ }
219067
+ add(
219068
+ node,
219069
+ key2,
219070
+ limitCall ? "limit" : "boolean",
219071
+ limitCall ? "usage_reporter" : "server_enforcement",
219072
+ limitCall ? "Application usage or limit check" : "Application access check"
219073
+ );
219074
+ }
219075
+ }
219076
+ if (import_typescript.default.isJsxOpeningElement(node) || import_typescript.default.isJsxSelfClosingElement(node)) {
219077
+ if (/^(FeatureGate|EntitlementGate|CapabilityGate)$/.test(
219078
+ node.tagName.getText(file2)
219079
+ )) {
219080
+ for (const prop of node.attributes.properties)
219081
+ if (import_typescript.default.isJsxAttribute(prop) && /^(featureKey|feature|capability)$/.test(prop.name.getText(file2)))
219082
+ add(
219083
+ prop,
219084
+ prop.initializer && import_typescript.default.isJsxExpression(prop.initializer) ? literalText(prop.initializer.expression) : literalText(prop.initializer),
219085
+ "boolean",
219086
+ "browser_presentation",
219087
+ "Application feature visibility gate"
219088
+ );
219089
+ }
219090
+ }
219091
+ if (import_typescript.default.isPropertyAssignment(node)) {
219092
+ const key2 = node.name.getText(file2).replace(/["']/g, "");
219093
+ if (/^(usageKey|limitKey|meterKey|featureLimit)$/.test(key2))
219094
+ add(
219095
+ node,
219096
+ literalText(node.initializer),
219097
+ "limit",
219098
+ "usage_reporter",
219099
+ "Application usage or limit declaration"
219100
+ );
219101
+ if (/^(deniedFeatureKey|featureDenied|onFeatureDenied)$/.test(key2))
219102
+ add(
219103
+ node,
219104
+ literalText(node.initializer),
219105
+ "boolean",
219106
+ "funnel_trigger",
219107
+ "Application denied-access trigger"
219108
+ );
219109
+ }
219110
+ import_typescript.default.forEachChild(node, visit);
219111
+ };
219112
+ visit(file2);
219113
+ return findings;
219114
+ }
219115
+
219116
+ // src/setup-pricing.ts
219117
+ var import_typescript2 = __toESM(require_typescript(), 1);
218950
219118
  var import_yaml = __toESM(require_dist(), 1);
218951
219119
  var PricingExtractionError = class extends Error {
218952
219120
  constructor(code, message) {
@@ -218962,29 +219130,29 @@ var unsupported = () => new PricingExtractionError(
218962
219130
  var object = (v) => v !== null && typeof v === "object" && !Array.isArray(v) ? v : null;
218963
219131
  var safeKey = (v) => typeof v === "string" && /^[a-z][a-z0-9_.-]{0,79}$/.test(v);
218964
219132
  var safeProperty = (key2) => !["__proto__", "constructor", "prototype"].includes(key2);
218965
- function declarations(source) {
218966
- const file2 = import_typescript.default.createSourceFile(
219133
+ function declarations(source, featuresOnly = false) {
219134
+ const file2 = import_typescript2.default.createSourceFile(
218967
219135
  "pricing.ts",
218968
219136
  source,
218969
- import_typescript.default.ScriptTarget.Latest,
219137
+ import_typescript2.default.ScriptTarget.Latest,
218970
219138
  true,
218971
- import_typescript.default.ScriptKind.TSX
219139
+ import_typescript2.default.ScriptKind.TSX
218972
219140
  );
218973
219141
  const values = /* @__PURE__ */ new Map();
218974
219142
  const roots = [];
218975
219143
  const planName = /^(plans?|pricing|tiers?|billingCatalog|planCatalog|subscriptionPlans)$/i;
218976
219144
  const containsAccess = (node, fields = /^(features|capabilities|quotas)$/) => {
218977
- if (import_typescript.default.isPropertyAssignment(node) && fields.test(node.name.getText(file2).replace(/["']/g, "")))
219145
+ if (import_typescript2.default.isPropertyAssignment(node) && fields.test(node.name.getText(file2).replace(/["']/g, "")))
218978
219146
  return true;
218979
- return import_typescript.default.forEachChild(
219147
+ return import_typescript2.default.forEachChild(
218980
219148
  node,
218981
219149
  (child) => containsAccess(child, fields) ? true : void 0
218982
219150
  ) ?? false;
218983
219151
  };
218984
219152
  for (const statement of file2.statements) {
218985
- if (import_typescript.default.isVariableStatement(statement))
219153
+ if (import_typescript2.default.isVariableStatement(statement))
218986
219154
  for (const declaration of statement.declarationList.declarations) {
218987
- if (import_typescript.default.isIdentifier(declaration.name) && declaration.initializer) {
219155
+ if (import_typescript2.default.isIdentifier(declaration.name) && declaration.initializer && isProductNode(declaration)) {
218988
219156
  values.set(declaration.name.text, declaration.initializer);
218989
219157
  if (planName.test(declaration.name.text) || containsAccess(declaration.initializer) && containsAccess(
218990
219158
  declaration.initializer,
@@ -218993,50 +219161,54 @@ function declarations(source) {
218993
219161
  roots.push(declaration.initializer);
218994
219162
  }
218995
219163
  }
218996
- if (import_typescript.default.isExportAssignment(statement) && containsAccess(statement.expression))
219164
+ if (import_typescript2.default.isExportAssignment(statement) && containsAccess(statement.expression))
218997
219165
  roots.push(statement.expression);
218998
219166
  }
218999
219167
  function read(node, depth = 0, locals = /* @__PURE__ */ new Map()) {
219000
219168
  if (depth > 30) throw unsupported();
219001
219169
  const next = (value) => read(value, depth + 1, locals);
219002
- if (import_typescript.default.isAsExpression(node) || import_typescript.default.isSatisfiesExpression(node) || import_typescript.default.isParenthesizedExpression(node))
219170
+ if (import_typescript2.default.isAsExpression(node) || import_typescript2.default.isSatisfiesExpression(node) || import_typescript2.default.isParenthesizedExpression(node))
219003
219171
  return next(node.expression);
219004
- if (import_typescript.default.isStringLiteral(node) || import_typescript.default.isNoSubstitutionTemplateLiteral(node))
219172
+ if (import_typescript2.default.isStringLiteral(node) || import_typescript2.default.isNoSubstitutionTemplateLiteral(node))
219005
219173
  return node.text;
219006
- if (import_typescript.default.isNumericLiteral(node)) return Number(node.text.replaceAll("_", ""));
219007
- if (node.kind === import_typescript.default.SyntaxKind.TrueKeyword) return true;
219008
- if (node.kind === import_typescript.default.SyntaxKind.FalseKeyword) return false;
219009
- if (import_typescript.default.isIdentifier(node)) {
219174
+ if (import_typescript2.default.isNumericLiteral(node)) return Number(node.text.replaceAll("_", ""));
219175
+ if (node.kind === import_typescript2.default.SyntaxKind.TrueKeyword) return true;
219176
+ if (node.kind === import_typescript2.default.SyntaxKind.FalseKeyword) return false;
219177
+ if (import_typescript2.default.isIdentifier(node)) {
219010
219178
  if (locals.has(node.text)) return locals.get(node.text);
219011
219179
  if (values.has(node.text)) return next(values.get(node.text));
219012
219180
  }
219013
- if (import_typescript.default.isArrayLiteralExpression(node))
219181
+ if (import_typescript2.default.isArrayLiteralExpression(node))
219014
219182
  return node.elements.flatMap((n) => {
219015
- if (!import_typescript.default.isSpreadElement(n)) return [next(n)];
219183
+ if (!import_typescript2.default.isSpreadElement(n)) return [next(n)];
219016
219184
  const spread = next(n.expression);
219017
219185
  if (!Array.isArray(spread)) throw unsupported();
219018
219186
  return spread;
219019
219187
  });
219020
- if (import_typescript.default.isObjectLiteralExpression(node)) {
219188
+ if (import_typescript2.default.isObjectLiteralExpression(node)) {
219021
219189
  const result3 = /* @__PURE__ */ Object.create(null);
219022
219190
  for (const property of node.properties) {
219023
- if (import_typescript.default.isSpreadAssignment(property)) {
219191
+ if (import_typescript2.default.isSpreadAssignment(property)) {
219024
219192
  const spread = object(next(property.expression));
219025
219193
  if (!spread) throw unsupported();
219026
219194
  Object.assign(result3, spread);
219027
219195
  continue;
219028
219196
  }
219029
- if (!import_typescript.default.isPropertyAssignment(property) || import_typescript.default.isComputedPropertyName(property.name))
219197
+ if (!import_typescript2.default.isPropertyAssignment(property) || import_typescript2.default.isComputedPropertyName(property.name))
219030
219198
  throw unsupported();
219031
219199
  const key2 = property.name.getText(file2).replace(/^["']|["']$/g, "");
219032
219200
  if (!safeProperty(key2)) throw unsupported();
219201
+ if (featuresOnly && /^(prices|stripePriceId|priceId|stripeProductId|productKey)$/.test(
219202
+ key2
219203
+ ))
219204
+ continue;
219033
219205
  result3[key2] = next(property.initializer);
219034
219206
  }
219035
219207
  return result3;
219036
219208
  }
219037
- if (import_typescript.default.isCallExpression(node) && import_typescript.default.isPropertyAccessExpression(node.expression)) {
219209
+ if (import_typescript2.default.isCallExpression(node) && import_typescript2.default.isPropertyAccessExpression(node.expression)) {
219038
219210
  const callee = node.expression;
219039
- if (import_typescript.default.isIdentifier(callee.expression) && callee.expression.text === "Object" && !values.has("Object") && callee.name.text === "fromEntries" && node.arguments.length === 1) {
219211
+ if (import_typescript2.default.isIdentifier(callee.expression) && callee.expression.text === "Object" && !values.has("Object") && callee.name.text === "fromEntries" && node.arguments.length === 1) {
219040
219212
  const entries = next(node.arguments[0]);
219041
219213
  if (!Array.isArray(entries) || entries.length > 1e4)
219042
219214
  throw unsupported();
@@ -219051,7 +219223,7 @@ function declarations(source) {
219051
219223
  if (callee.name.text === "map" && node.arguments.length === 1) {
219052
219224
  const array2 = next(callee.expression);
219053
219225
  const callback = node.arguments[0];
219054
- if (!Array.isArray(array2) || array2.length > 1e4 || !import_typescript.default.isArrowFunction(callback) || callback.parameters.length !== 1 || !import_typescript.default.isIdentifier(callback.parameters[0].name) || import_typescript.default.isBlock(callback.body))
219226
+ if (!Array.isArray(array2) || array2.length > 1e4 || !import_typescript2.default.isArrowFunction(callback) || callback.parameters.length !== 1 || !import_typescript2.default.isIdentifier(callback.parameters[0].name) || import_typescript2.default.isBlock(callback.body))
219055
219227
  throw unsupported();
219056
219228
  const parameter = callback.parameters[0].name.text;
219057
219229
  return array2.map(
@@ -219067,13 +219239,13 @@ function declarations(source) {
219067
219239
  }
219068
219240
  return roots.map((node) => read(node));
219069
219241
  }
219070
- function extractSetupPricing(source, kind, catalogPrices = []) {
219242
+ function extractSetupPricing(source, kind, catalogPrices = [], options = {}) {
219071
219243
  if (source.length > 2e6)
219072
219244
  throw new PricingExtractionError(
219073
219245
  "needs_review",
219074
219246
  "Pricing file exceeds the 2 MB per-file limit."
219075
219247
  );
219076
- const documents = kind === "typescript" ? declarations(source) : kind === "json" ? [JSON.parse(source)] : [
219248
+ const documents = kind === "typescript" ? declarations(source, options.featuresOnly) : kind === "json" ? [JSON.parse(source)] : [
219077
219249
  (0, import_yaml.parseDocument)(source, { uniqueKeys: true }).toJS({
219078
219250
  maxAliasCount: 10
219079
219251
  })
@@ -219108,13 +219280,19 @@ function extractSetupPricing(source, kind, catalogPrices = []) {
219108
219280
  for (const [feature, access2] of entries) {
219109
219281
  if (!safeKey(feature) || !safeProperty(feature) || !(typeof access2 === "boolean" || access2 === "unlimited" || typeof access2 === "number" && Number.isFinite(access2) && access2 >= 0))
219110
219282
  throw unsupported();
219111
- if (features[feature] === false && access2 !== false)
219112
- throw unsupported();
219113
- features[feature] = access2;
219283
+ const previous = features[feature];
219284
+ if (previous !== void 0 && previous !== access2) {
219285
+ if (previous === false || access2 === false || previous !== true && access2 !== true)
219286
+ throw new PricingExtractionError(
219287
+ "needs_review",
219288
+ "Conflicting access values for the same feature."
219289
+ );
219290
+ }
219291
+ features[feature] = access2 === true && previous !== void 0 ? previous : access2;
219114
219292
  }
219115
219293
  }
219116
219294
  const rawPrices = Array.isArray(row.prices) ? row.prices : object(row.prices) ? Object.values(row.prices) : row.stripePriceId ?? row.priceId ? [{ key: row.stripePriceId ?? row.priceId }] : [];
219117
- const prices = rawPrices.map((value2) => {
219295
+ const prices = (options.featuresOnly ? [] : rawPrices).map((value2) => {
219118
219296
  const price = typeof value2 === "string" ? value2 : object(value2)?.key ?? object(value2)?.stripePriceId;
219119
219297
  if (typeof price === "string" && /^price_[A-Za-z0-9]+$/.test(price))
219120
219298
  return { key: price };
@@ -219145,6 +219323,18 @@ function extractSetupPricing(source, kind, catalogPrices = []) {
219145
219323
  plans.set(key2, plan);
219146
219324
  }
219147
219325
  }
219326
+ const featureModels = /* @__PURE__ */ new Map();
219327
+ for (const plan of plans.values())
219328
+ for (const [key2, value] of Object.entries(plan.features)) {
219329
+ const models = featureModels.get(key2) ?? /* @__PURE__ */ new Set();
219330
+ models.add(typeof value === "boolean" ? "boolean" : "limit");
219331
+ featureModels.set(key2, models);
219332
+ }
219333
+ if ([...featureModels.values()].some((models) => models.size > 1))
219334
+ throw new PricingExtractionError(
219335
+ "needs_review",
219336
+ "A feature mixes capability and quota values across plans. Review its access model; no conversion was guessed."
219337
+ );
219148
219338
  if (!plans.size)
219149
219339
  throw new PricingExtractionError(
219150
219340
  "no_declarations",
@@ -219158,12 +219348,374 @@ function extractSetupPricing(source, kind, catalogPrices = []) {
219158
219348
  return [...plans.values()];
219159
219349
  }
219160
219350
 
219161
- // src/setup-run.ts
219162
- import { createHash as createHash3 } from "node:crypto";
219351
+ // src/plan-analysis.ts
219352
+ var import_typescript3 = __toESM(require_typescript(), 1);
219353
+ function effect(node) {
219354
+ let result3 = node.kind === import_typescript3.default.SyntaxKind.FalseKeyword ? "deny" : null;
219355
+ const visit = (child) => {
219356
+ if (child !== node && (import_typescript3.default.isFunctionLike(child) || !isProductNode(child)))
219357
+ return;
219358
+ if (import_typescript3.default.isReturnStatement(child)) {
219359
+ if (child.expression?.kind === import_typescript3.default.SyntaxKind.FalseKeyword || child.expression?.kind === import_typescript3.default.SyntaxKind.NullKeyword)
219360
+ result3 = "deny";
219361
+ }
219362
+ if (import_typescript3.default.isThrowStatement(child)) {
219363
+ if (/upgrade|paywall|forbidden|entitlement|feature.+(?:denied|unavailable)|plan.+(?:required|does not|cannot)|quota|limit exceeded/i.test(
219364
+ child.expression.getText()
219365
+ ))
219366
+ result3 = "deny";
219367
+ }
219368
+ if (import_typescript3.default.isCallExpression(child)) {
219369
+ const name = import_typescript3.default.isIdentifier(child.expression) ? child.expression.text : import_typescript3.default.isPropertyAccessExpression(child.expression) ? child.expression.name.text : "";
219370
+ if (/^(forbidden|denyAccess|requireUpgrade|showPaywall|denyFeatureAccess)$/i.test(
219371
+ name
219372
+ ))
219373
+ result3 = "deny";
219374
+ if (/^(redirect|navigate|push|replace)$/.test(name) && child.arguments.some(
219375
+ (a) => /upgrade|paywall/.test(literalText(a) ?? "")
219376
+ ))
219377
+ result3 = "deny";
219378
+ if (/^(status|sendStatus)$/.test(name) && child.arguments.some((a) => import_typescript3.default.isNumericLiteral(a) && a.text === "403"))
219379
+ result3 = "deny";
219380
+ }
219381
+ if (import_typescript3.default.isPropertyAssignment(child) && child.name.getText().replace(/["']/g, "") === "status" && import_typescript3.default.isNumericLiteral(child.initializer) && child.initializer.text === "403")
219382
+ result3 = "deny";
219383
+ import_typescript3.default.forEachChild(child, visit);
219384
+ };
219385
+ visit(node);
219386
+ return result3;
219387
+ }
219388
+ function conditionalEffect(node) {
219389
+ let conditional = false;
219390
+ const visit = (child) => {
219391
+ if (import_typescript3.default.isFunctionLike(child)) return;
219392
+ if (import_typescript3.default.isIfStatement(child) || import_typescript3.default.isConditionalExpression(child) || import_typescript3.default.isSwitchStatement(child) || import_typescript3.default.isIterationStatement(child, false))
219393
+ conditional = true;
219394
+ import_typescript3.default.forEachChild(child, visit);
219395
+ };
219396
+ visit(node);
219397
+ return conditional;
219398
+ }
219399
+ function planRestrictionEvidence(path, source) {
219400
+ if (nonProductPath.test(path)) return [];
219401
+ const file2 = parseApplicationSource(path, source);
219402
+ const results = [];
219403
+ function consequence(node) {
219404
+ const conditionPolarity = (condition, polarity) => {
219405
+ let cursor = condition;
219406
+ let inverted = false;
219407
+ while (import_typescript3.default.isParenthesizedExpression(cursor) || import_typescript3.default.isPrefixUnaryExpression(cursor) && cursor.operator === import_typescript3.default.SyntaxKind.ExclamationToken) {
219408
+ if (import_typescript3.default.isParenthesizedExpression(cursor)) cursor = cursor.expression;
219409
+ else {
219410
+ inverted = !inverted;
219411
+ cursor = cursor.operand;
219412
+ }
219413
+ }
219414
+ if (cursor !== node) return "unclear";
219415
+ return inverted ? polarity === "deny" ? "grant" : polarity === "grant" ? "deny" : "unclear" : polarity;
219416
+ };
219417
+ let child = node;
219418
+ for (let parent = node.parent; parent; child = parent, parent = parent.parent) {
219419
+ if (import_typescript3.default.isIfStatement(parent) && child === parent.expression) {
219420
+ if (effect(parent.thenStatement) === "deny")
219421
+ return {
219422
+ shape: "boolean",
219423
+ polarity: conditionalEffect(parent.thenStatement) ? "unclear" : conditionPolarity(parent.expression, "deny")
219424
+ };
219425
+ if (parent.elseStatement && effect(parent.elseStatement) === "deny")
219426
+ return {
219427
+ shape: "boolean",
219428
+ polarity: conditionalEffect(parent.elseStatement) ? "unclear" : conditionPolarity(parent.expression, "grant")
219429
+ };
219430
+ return null;
219431
+ }
219432
+ if (import_typescript3.default.isConditionalExpression(parent) && child === parent.condition) {
219433
+ const symbol2 = enclosingSymbol(parent);
219434
+ if (/limit|quota|capacity|max(?:imum)?|allowance/i.test(symbol2) && import_typescript3.default.isNumericLiteral(parent.whenTrue) && import_typescript3.default.isNumericLiteral(parent.whenFalse))
219435
+ return { shape: "limit", polarity: "unclear" };
219436
+ if (import_typescript3.default.isJsxElement(parent.whenTrue) || import_typescript3.default.isJsxSelfClosingElement(parent.whenTrue) || import_typescript3.default.isJsxElement(parent.whenFalse) || import_typescript3.default.isJsxSelfClosingElement(parent.whenFalse))
219437
+ return { shape: "presentation", polarity: "unclear" };
219438
+ if (effect(parent.whenTrue) === "deny")
219439
+ return {
219440
+ shape: "boolean",
219441
+ polarity: conditionPolarity(parent.condition, "deny")
219442
+ };
219443
+ if (effect(parent.whenFalse) === "deny")
219444
+ return {
219445
+ shape: "boolean",
219446
+ polarity: conditionPolarity(parent.condition, "grant")
219447
+ };
219448
+ return null;
219449
+ }
219450
+ if (import_typescript3.default.isVariableDeclaration(parent) && child === parent.initializer && import_typescript3.default.isIdentifier(parent.name)) {
219451
+ const scope = parent.parent.parent.parent;
219452
+ if (!scope) return null;
219453
+ let found = null;
219454
+ const search = (candidate) => {
219455
+ if (candidate === parent || candidate !== scope && import_typescript3.default.isFunctionLike(candidate))
219456
+ return;
219457
+ if (import_typescript3.default.isIdentifier(candidate) && candidate.text === parent.name.getText() && candidate.parent !== parent) {
219458
+ let ancestor = candidate.parent;
219459
+ while (ancestor && !import_typescript3.default.isIfStatement(ancestor) && !import_typescript3.default.isStatement(ancestor))
219460
+ ancestor = ancestor.parent;
219461
+ if (ancestor && import_typescript3.default.isIfStatement(ancestor) && effect(ancestor.thenStatement) === "deny")
219462
+ found = { shape: "boolean", polarity: "unclear" };
219463
+ }
219464
+ import_typescript3.default.forEachChild(candidate, search);
219465
+ };
219466
+ search(scope);
219467
+ return found;
219468
+ }
219469
+ if (import_typescript3.default.isStatement(parent) || import_typescript3.default.isFunctionLike(parent)) return null;
219470
+ }
219471
+ return null;
219472
+ }
219473
+ const visit = (node) => {
219474
+ if (!isProductNode(node)) return;
219475
+ if (import_typescript3.default.isBinaryExpression(node) && [
219476
+ import_typescript3.default.SyntaxKind.EqualsEqualsEqualsToken,
219477
+ import_typescript3.default.SyntaxKind.EqualsEqualsToken,
219478
+ import_typescript3.default.SyntaxKind.ExclamationEqualsEqualsToken,
219479
+ import_typescript3.default.SyntaxKind.ExclamationEqualsToken
219480
+ ].includes(node.operatorToken.kind)) {
219481
+ const left = node.left.getText(file2);
219482
+ if (/plan|tier|subscription|package/i.test(left)) {
219483
+ const right = node.right;
219484
+ const literal2 = literalText(right);
219485
+ const reference = import_typescript3.default.isIdentifier(right) || import_typescript3.default.isPropertyAccessExpression(right) ? right.getText(file2) : null;
219486
+ const outcome = consequence(node);
219487
+ if (outcome && (literal2 || reference)) {
219488
+ const negated = node.operatorToken.kind === import_typescript3.default.SyntaxKind.ExclamationEqualsEqualsToken || node.operatorToken.kind === import_typescript3.default.SyntaxKind.ExclamationEqualsToken;
219489
+ results.push({
219490
+ ...outcome,
219491
+ polarity: negated ? outcome.polarity === "deny" ? "grant" : outcome.polarity === "grant" ? "deny" : "unclear" : outcome.polarity,
219492
+ literal: literal2,
219493
+ reference,
219494
+ negated: node.operatorToken.kind === import_typescript3.default.SyntaxKind.ExclamationEqualsEqualsToken || node.operatorToken.kind === import_typescript3.default.SyntaxKind.ExclamationEqualsToken,
219495
+ line: file2.getLineAndCharacterOfPosition(node.getStart(file2)).line + 1,
219496
+ symbol: enclosingSymbol(node)
219497
+ });
219498
+ }
219499
+ }
219500
+ }
219501
+ import_typescript3.default.forEachChild(node, visit);
219502
+ };
219503
+ visit(file2);
219504
+ return results;
219505
+ }
219506
+
219507
+ // src/plan-constants.ts
219508
+ var import_typescript4 = __toESM(require_typescript(), 1);
219509
+ import { posix } from "node:path";
219510
+ function planConstantResolver(sources) {
219511
+ const modules = /* @__PURE__ */ new Map();
219512
+ for (const [path, source] of sources) {
219513
+ const module = {
219514
+ values: /* @__PURE__ */ new Map(),
219515
+ imports: /* @__PURE__ */ new Map(),
219516
+ exports: /* @__PURE__ */ new Set()
219517
+ };
219518
+ modules.set(path, module);
219519
+ const file2 = parseApplicationSource(path, source);
219520
+ const add = (name, expression, exported) => {
219521
+ module.values.set(name, expression);
219522
+ if (exported) module.exports.add(name.split(".")[0]);
219523
+ };
219524
+ for (const statement of file2.statements) {
219525
+ if (!isProductNode(statement)) continue;
219526
+ const exported = import_typescript4.default.canHaveModifiers(statement) && Boolean(
219527
+ import_typescript4.default.getModifiers(statement)?.some((m) => m.kind === import_typescript4.default.SyntaxKind.ExportKeyword)
219528
+ );
219529
+ if (import_typescript4.default.isImportDeclaration(statement) && import_typescript4.default.isStringLiteral(statement.moduleSpecifier) && !statement.importClause?.isTypeOnly) {
219530
+ const clause = statement.importClause;
219531
+ const source2 = statement.moduleSpecifier.text;
219532
+ if (clause?.name)
219533
+ module.imports.set(clause.name.text, { source: source2, name: "default" });
219534
+ const bindings = clause?.namedBindings;
219535
+ if (bindings && import_typescript4.default.isNamedImports(bindings))
219536
+ for (const element of bindings.elements) {
219537
+ if (!element.isTypeOnly)
219538
+ module.imports.set(element.name.text, {
219539
+ source: source2,
219540
+ name: element.propertyName?.text ?? element.name.text
219541
+ });
219542
+ }
219543
+ else if (bindings && import_typescript4.default.isNamespaceImport(bindings))
219544
+ module.imports.set(bindings.name.text, { source: source2, name: "" });
219545
+ }
219546
+ if (import_typescript4.default.isVariableStatement(statement))
219547
+ for (const declaration of statement.declarationList.declarations) {
219548
+ if (!import_typescript4.default.isIdentifier(declaration.name) || !declaration.initializer || !isProductNode(declaration))
219549
+ continue;
219550
+ let expression = declaration.initializer;
219551
+ while (import_typescript4.default.isAsExpression(expression) || import_typescript4.default.isSatisfiesExpression(expression) || import_typescript4.default.isParenthesizedExpression(expression))
219552
+ expression = expression.expression;
219553
+ const name = declaration.name.text;
219554
+ add(name, expression, exported);
219555
+ if (import_typescript4.default.isObjectLiteralExpression(expression))
219556
+ for (const property of expression.properties) {
219557
+ if (import_typescript4.default.isPropertyAssignment(property) && !import_typescript4.default.isComputedPropertyName(property.name))
219558
+ add(
219559
+ `${name}.${property.name.getText(file2).replace(/["']/g, "")}`,
219560
+ property.initializer,
219561
+ exported
219562
+ );
219563
+ }
219564
+ }
219565
+ if (import_typescript4.default.isEnumDeclaration(statement))
219566
+ for (const member of statement.members) {
219567
+ if (member.initializer && !import_typescript4.default.isComputedPropertyName(member.name))
219568
+ add(
219569
+ `${statement.name.text}.${member.name.getText(file2).replace(/["']/g, "")}`,
219570
+ member.initializer,
219571
+ exported
219572
+ );
219573
+ }
219574
+ if (import_typescript4.default.isExportAssignment(statement))
219575
+ add("default", statement.expression, true);
219576
+ }
219577
+ }
219578
+ const resolve6 = (path, reference, depth = 0) => {
219579
+ if (depth > 12) return null;
219580
+ const module = modules.get(path);
219581
+ if (!module) return null;
219582
+ const value = module.values.get(reference);
219583
+ if (value) {
219584
+ const literal2 = literalText(value);
219585
+ if (literal2 !== null) return literal2.toLowerCase();
219586
+ if (import_typescript4.default.isIdentifier(value) || import_typescript4.default.isPropertyAccessExpression(value))
219587
+ return resolve6(path, value.getText(), depth + 1);
219588
+ return null;
219589
+ }
219590
+ const [first, ...tail] = reference.split(".");
219591
+ const imported = module.imports.get(first);
219592
+ if (!imported?.source.startsWith(".")) return null;
219593
+ const base = posix.normalize(
219594
+ posix.join(posix.dirname(path), imported.source)
219595
+ );
219596
+ if (base.startsWith("../")) return null;
219597
+ const stem = base.replace(/\.[cm]?jsx?$/, "");
219598
+ const target = [
219599
+ base,
219600
+ ...[
219601
+ ".ts",
219602
+ ".tsx",
219603
+ ".js",
219604
+ ".jsx",
219605
+ ".mjs",
219606
+ ".cjs",
219607
+ "/index.ts",
219608
+ "/index.js"
219609
+ ].map((ext) => stem + ext)
219610
+ ].find((candidate) => modules.has(candidate));
219611
+ if (!target) return null;
219612
+ const member = [imported.name, ...tail].filter(Boolean).join(".");
219613
+ if (!modules.get(target).exports.has(member.split(".")[0])) return null;
219614
+ return resolve6(target, member, depth + 1);
219615
+ };
219616
+ return (path, reference, line) => {
219617
+ if (line !== void 0) {
219618
+ const file2 = parseApplicationSource(path, sources.get(path) ?? "");
219619
+ const root = reference.split(".")[0];
219620
+ let shadowed = false;
219621
+ const binds = (name) => import_typescript4.default.isIdentifier(name) ? name.text === root : name.elements.some(
219622
+ (element) => import_typescript4.default.isBindingElement(element) && binds(element.name)
219623
+ );
219624
+ const containsLine = (node) => file2.getLineAndCharacterOfPosition(node.getStart(file2)).line + 1 <= line && file2.getLineAndCharacterOfPosition(node.end).line + 1 >= line;
219625
+ const visit = (node) => {
219626
+ if (!containsLine(node)) return;
219627
+ if (import_typescript4.default.isFunctionLike(node) && node.parameters.some((p) => binds(p.name)))
219628
+ shadowed = true;
219629
+ if (import_typescript4.default.isCatchClause(node) && node.variableDeclaration && binds(node.variableDeclaration.name))
219630
+ shadowed = true;
219631
+ if (import_typescript4.default.isBlock(node)) {
219632
+ for (const statement of node.statements) {
219633
+ if (import_typescript4.default.isVariableStatement(statement) && statement.declarationList.declarations.some((d) => binds(d.name)))
219634
+ shadowed = true;
219635
+ if ((import_typescript4.default.isFunctionDeclaration(statement) || import_typescript4.default.isClassDeclaration(statement)) && statement.name?.text === root)
219636
+ shadowed = true;
219637
+ }
219638
+ }
219639
+ import_typescript4.default.forEachChild(node, visit);
219640
+ };
219641
+ visit(file2);
219642
+ if (shadowed) return null;
219643
+ }
219644
+ return resolve6(path, reference);
219645
+ };
219646
+ }
219647
+
219648
+ // src/discovery-coverage.ts
219649
+ var import_typescript5 = __toESM(require_typescript(), 1);
219163
219650
  import { execFile as execFile3 } from "node:child_process";
219164
219651
  import { promisify as promisify3 } from "node:util";
219165
- import { readFile as readFile5, writeFile as writeFile3, mkdir as mkdir3 } from "node:fs/promises";
219166
- import { join as join4 } from "node:path";
219652
+ import { lstat as lstat2, readFile as readFile3 } from "node:fs/promises";
219653
+ import { join as join2 } from "node:path";
219654
+
219655
+ // src/source-scope.ts
219656
+ import { execFile as execFile2 } from "node:child_process";
219657
+ import { promisify as promisify2 } from "node:util";
219658
+ var exec2 = promisify2(execFile2);
219659
+ async function repositorySourceScope(cwd2) {
219660
+ try {
219661
+ await exec2("git", ["rev-parse", "--is-inside-work-tree"], { cwd: cwd2 });
219662
+ } catch (error51) {
219663
+ const failure = error51;
219664
+ if (failure.code === "ENOENT" || failure.stderr?.includes("not a git repository"))
219665
+ return (_path) => true;
219666
+ throw new Error(
219667
+ "Cannot read repository source scope. Check Git access and retry."
219668
+ );
219669
+ }
219670
+ let stdout;
219671
+ try {
219672
+ ({ stdout } = await exec2(
219673
+ "git",
219674
+ [
219675
+ "ls-files",
219676
+ "--cached",
219677
+ "--others",
219678
+ "--exclude-standard",
219679
+ "-z",
219680
+ "--",
219681
+ "."
219682
+ ],
219683
+ {
219684
+ cwd: cwd2,
219685
+ maxBuffer: 32 * 1024 * 1024
219686
+ }
219687
+ ));
219688
+ } catch {
219689
+ throw new Error(
219690
+ "Cannot list repository sources. Check Git access and retry."
219691
+ );
219692
+ }
219693
+ const included = /* @__PURE__ */ new Set([""]);
219694
+ for (const path of stdout.split("\0").filter(Boolean)) {
219695
+ included.add(path);
219696
+ let end = path.lastIndexOf("/");
219697
+ while (end > 0) {
219698
+ included.add(path.slice(0, end));
219699
+ end = path.lastIndexOf("/", end - 1);
219700
+ }
219701
+ }
219702
+ return (path) => included.has(path);
219703
+ }
219704
+
219705
+ // src/feature-setup.ts
219706
+ var import_yaml2 = __toESM(require_dist(), 1);
219707
+ import { createHash as createHash2, randomUUID } from "node:crypto";
219708
+ import {
219709
+ access,
219710
+ mkdir,
219711
+ readFile as readFile2,
219712
+ readdir,
219713
+ rename,
219714
+ rm,
219715
+ lstat,
219716
+ writeFile
219717
+ } from "node:fs/promises";
219718
+ import { dirname, extname, join, relative, resolve as resolve2 } from "node:path";
219167
219719
 
219168
219720
  // node_modules/zod/v4/classic/external.js
219169
219721
  var external_exports = {};
@@ -233679,71 +234231,6 @@ function date4(params) {
233679
234231
  // node_modules/zod/v4/classic/external.js
233680
234232
  config(en_default());
233681
234233
 
233682
- // src/source-scope.ts
233683
- import { execFile as execFile2 } from "node:child_process";
233684
- import { promisify as promisify2 } from "node:util";
233685
- var exec2 = promisify2(execFile2);
233686
- async function repositorySourceScope(cwd2) {
233687
- try {
233688
- await exec2("git", ["rev-parse", "--is-inside-work-tree"], { cwd: cwd2 });
233689
- } catch (error51) {
233690
- const failure = error51;
233691
- if (failure.code === "ENOENT" || failure.stderr?.includes("not a git repository"))
233692
- return (_path) => true;
233693
- throw new Error(
233694
- "Cannot read repository source scope. Check Git access and retry."
233695
- );
233696
- }
233697
- let stdout;
233698
- try {
233699
- ({ stdout } = await exec2(
233700
- "git",
233701
- [
233702
- "ls-files",
233703
- "--cached",
233704
- "--others",
233705
- "--exclude-standard",
233706
- "-z",
233707
- "--",
233708
- "."
233709
- ],
233710
- {
233711
- cwd: cwd2,
233712
- maxBuffer: 32 * 1024 * 1024
233713
- }
233714
- ));
233715
- } catch {
233716
- throw new Error(
233717
- "Cannot list repository sources. Check Git access and retry."
233718
- );
233719
- }
233720
- const included = /* @__PURE__ */ new Set([""]);
233721
- for (const path of stdout.split("\0").filter(Boolean)) {
233722
- included.add(path);
233723
- let end = path.lastIndexOf("/");
233724
- while (end > 0) {
233725
- included.add(path.slice(0, end));
233726
- end = path.lastIndexOf("/", end - 1);
233727
- }
233728
- }
233729
- return (path) => included.has(path);
233730
- }
233731
-
233732
- // src/feature-setup.ts
233733
- var import_yaml2 = __toESM(require_dist(), 1);
233734
- import { createHash as createHash2, randomUUID } from "node:crypto";
233735
- import {
233736
- access,
233737
- mkdir,
233738
- readFile as readFile2,
233739
- readdir,
233740
- rename,
233741
- rm,
233742
- lstat,
233743
- writeFile
233744
- } from "node:fs/promises";
233745
- import { dirname, extname, join, relative, resolve as resolve2 } from "node:path";
233746
-
233747
234234
  // src/runtime-contracts.js
233748
234235
  import { createHash } from "node:crypto";
233749
234236
  var DIRECT_API_AGENT_HANDOFF_VERSION = "2026-06-28.1";
@@ -234429,9 +234916,9 @@ function boundedTraitValue(value) {
234429
234916
  }
234430
234917
  function pickAccountTraits(records, keys = accountTraitKeys) {
234431
234918
  const traits = {};
234432
- for (const record4 of records) {
234919
+ for (const record3 of records) {
234433
234920
  for (const key2 of keys) {
234434
- const value = boundedTraitValue(record4[key2]);
234921
+ const value = boundedTraitValue(record3[key2]);
234435
234922
  if (value !== void 0) traits[key2] = value;
234436
234923
  }
234437
234924
  }
@@ -235164,8 +235651,8 @@ function collectSemanticCandidates(payload, source) {
235164
235651
  records.push({ path: "event.properties", record: objectValue2(wrappedEvent.properties) });
235165
235652
  }
235166
235653
  return records.flatMap(
235167
- ({ path, record: record4 }) => ["semantic_type", "event_type"].flatMap((field) => {
235168
- const value = nonEmptyString(record4[field]);
235654
+ ({ path, record: record3 }) => ["semantic_type", "event_type"].flatMap((field) => {
235655
+ const value = nonEmptyString(record3[field]);
235169
235656
  return value ? [{ path: path ? `${path}.${field}` : field, value }] : [];
235170
235657
  })
235171
235658
  );
@@ -235890,6 +236377,7 @@ var featureBindingKinds = [
235890
236377
  "discovery"
235891
236378
  ];
235892
236379
  var defaultRoots = [
236380
+ ".",
235893
236381
  "app",
235894
236382
  "src",
235895
236383
  "lib",
@@ -235898,10 +236386,13 @@ var defaultRoots = [
235898
236386
  "apps",
235899
236387
  "packages",
235900
236388
  "server",
235901
- "client"
236389
+ "client",
236390
+ "config"
235902
236391
  ];
235903
236392
  var ignoredSegments = /* @__PURE__ */ new Set([
235904
236393
  ".claude",
236394
+ ".agents",
236395
+ ".codex",
235905
236396
  ".git",
235906
236397
  ".next",
235907
236398
  ".output",
@@ -236011,7 +236502,8 @@ async function exists(path) {
236011
236502
  }
236012
236503
  function allowedPath(path, excludes) {
236013
236504
  const normalized = path.replaceAll("\\", "/");
236014
- if (sensitivePathPattern.test(normalized)) return false;
236505
+ if (sensitivePathPattern.test(normalized) || nonProductPath.test(normalized))
236506
+ return false;
236015
236507
  const segments = normalized.split("/");
236016
236508
  if (segments.some(
236017
236509
  (segment) => ignoredSegments.has(segment) || /^\.next(?:[-.]|$)/.test(segment)
@@ -236033,7 +236525,7 @@ async function walkFiles(input) {
236033
236525
  if (seen.has(current)) continue;
236034
236526
  seen.add(current);
236035
236527
  const relativePath = safeRelative(input.cwd, current);
236036
- if (!relativePath || !inRepository(relativePath) || !allowedPath(relativePath, input.excludes))
236528
+ if (relativePath === null && current !== resolve2(input.cwd) || !inRepository(relativePath ?? "") || !allowedPath(relativePath ?? "", input.excludes))
236037
236529
  continue;
236038
236530
  let currentStat;
236039
236531
  try {
@@ -236046,7 +236538,9 @@ async function walkFiles(input) {
236046
236538
  entries.sort((left, right) => left.name.localeCompare(right.name)).forEach((entry) => queue.push(join(current, entry.name)));
236047
236539
  continue;
236048
236540
  }
236049
- if (currentStat.isFile() && supportedExtensions.has(extname(current))) {
236541
+ if (currentStat.isFile() && (supportedExtensions.has(extname(current)) || /\.(json|ya?ml)$/.test(current) && /(?:^|[\/._-])(plans?|pricing|entitlements?|catalog|tiers?|features|quotas)(?:[._-]|$)/i.test(
236542
+ relativePath ?? ""
236543
+ ))) {
236050
236544
  if (currentStat.size > 2e6) {
236051
236545
  oversizedFileCount++;
236052
236546
  continue;
@@ -236056,102 +236550,80 @@ async function walkFiles(input) {
236056
236550
  }
236057
236551
  return { files: files.sort(), oversizedFileCount };
236058
236552
  }
236059
- function nearestSymbol(lines, lineIndex) {
236060
- for (let index = lineIndex; index >= Math.max(0, lineIndex - 20); index -= 1) {
236061
- const match = lines[index]?.match(
236062
- /(?:export\s+)?(?:async\s+)?(?:function|class|const|let|var)\s+([A-Za-z_$][\w$]*)/
236063
- );
236064
- if (match?.[1]) return match[1];
236065
- }
236066
- return "module";
236067
- }
236068
236553
  function candidatesFromFile(path, source) {
236069
- const lines = source.split(/\r?\n/);
236070
- const candidates = [];
236071
- const patterns = [
236072
- {
236073
- accessModel: "boolean",
236074
- confidenceBasisPoints: 9800,
236075
- pattern: /(?:hasFeature\s*\(|checkFeature\s*\(|checkEntitlement\s*\(|isFeatureEnabled\s*\()["'`]([a-z][a-z0-9_.-]{1,79})["'`]/g,
236076
- bindingKind: "server_enforcement",
236077
- rationale: "Existing server Feature or entitlement check",
236078
- unit: null
236079
- },
236080
- {
236081
- accessModel: "boolean",
236082
- bindingKind: "browser_presentation",
236083
- confidenceBasisPoints: 9600,
236084
- pattern: /<FeatureGate[^>]*featureKey\s*=\s*["'`]([a-z][a-z0-9_.-]{1,79})["'`]/g,
236085
- rationale: "Existing browser Feature presentation gate",
236086
- unit: null
236087
- },
236088
- {
236089
- accessModel: "limit",
236090
- bindingKind: "usage_reporter",
236091
- confidenceBasisPoints: 9300,
236092
- pattern: /(?:usageKey|limitKey|meterKey|featureLimit)\s*[:=]\s*["'`]([a-z][a-z0-9_.-]{1,79})["'`]/g,
236093
- rationale: "Existing usage or limit key",
236094
- unit: "uses"
236095
- },
236096
- {
236097
- accessModel: "boolean",
236098
- bindingKind: "funnel_trigger",
236099
- confidenceBasisPoints: 8900,
236100
- pattern: /(?:deniedFeatureKey|featureDenied|onFeatureDenied)\s*[:=(]\s*["'`]([a-z][a-z0-9_.-]{1,79})["'`]/g,
236101
- rationale: "Denied-access Funnel trigger",
236102
- unit: null
236103
- },
236104
- {
236105
- accessModel: "boolean",
236106
- bindingKind: "discovery",
236107
- confidenceBasisPoints: 7600,
236108
- pattern: /(?:featureKey\s*[:=]\s*|(?:FEATURES?|ENTITLEMENTS?)\s*(?:=|:)\s*(?:\{|\[)[^\n]*?)["'`]([a-z][a-z0-9_.-]{1,79})["'`]/g,
236109
- rationale: "Feature or entitlement constant",
236110
- unit: null
236554
+ const named = namedFeatureEvidence(path, source).map(
236555
+ (evidence) => {
236556
+ const fingerprint3 = sha256(
236557
+ JSON.stringify([
236558
+ path,
236559
+ evidence.key,
236560
+ evidence.model,
236561
+ evidence.line,
236562
+ evidence.symbol
236563
+ ])
236564
+ );
236565
+ return {
236566
+ accessModel: evidence.model,
236567
+ bindingIdentityFingerprint: sha256(
236568
+ JSON.stringify([evidence.kind, evidence.key, evidence.symbol])
236569
+ ),
236570
+ bindingKind: evidence.kind,
236571
+ confidenceBasisPoints: evidence.kind === "server_enforcement" ? 9800 : 9e3,
236572
+ file: path,
236573
+ fingerprint: fingerprint3,
236574
+ id: fingerprint3.slice(0, 12),
236575
+ line: evidence.line,
236576
+ name: displayName(evidence.key),
236577
+ rationale: evidence.reason,
236578
+ suggestedKey: evidence.key,
236579
+ symbol: evidence.symbol,
236580
+ unit: null
236581
+ };
236111
236582
  }
236112
- ];
236113
- patterns.forEach((definition) => {
236114
- lines.forEach((line, lineIndex) => {
236115
- definition.pattern.lastIndex = 0;
236116
- let match;
236117
- while (match = definition.pattern.exec(line)) {
236118
- const key2 = stableKey(match[1] ?? "");
236119
- const symbol2 = nearestSymbol(lines, lineIndex);
236120
- const fingerprint3 = sha256(
236121
- JSON.stringify({
236122
- accessModel: definition.accessModel,
236123
- file: path,
236124
- key: key2,
236125
- line: lineIndex + 1,
236126
- symbol: symbol2
236127
- })
236128
- );
236129
- const bindingIdentityFingerprint = sha256(
236130
- JSON.stringify({
236131
- bindingKind: definition.bindingKind,
236132
- rationale: definition.rationale,
236133
- symbol: symbol2
236134
- })
236135
- );
236136
- candidates.push({
236137
- accessModel: definition.accessModel,
236138
- bindingIdentityFingerprint,
236139
- bindingKind: definition.bindingKind,
236140
- confidenceBasisPoints: definition.confidenceBasisPoints,
236141
- file: path,
236142
- fingerprint: fingerprint3,
236143
- id: fingerprint3.slice(0, 12),
236144
- line: lineIndex + 1,
236145
- name: displayName(key2),
236146
- rationale: definition.rationale,
236147
- suggestedKey: key2,
236148
- symbol: symbol2,
236149
- unit: definition.unit
236150
- });
236151
- }
236152
- });
236153
- });
236154
- return candidates;
236583
+ );
236584
+ if (nonProductPath.test(path)) return named;
236585
+ try {
236586
+ const plans = extractSetupPricing(
236587
+ source,
236588
+ /\.json$/.test(path) ? "json" : /\.ya?ml$/.test(path) ? "yaml" : "typescript",
236589
+ [],
236590
+ { featuresOnly: true }
236591
+ );
236592
+ const features = /* @__PURE__ */ new Map();
236593
+ for (const plan of plans)
236594
+ for (const [key2, value] of Object.entries(plan.features)) {
236595
+ const model = typeof value === "boolean" ? "boolean" : "limit";
236596
+ if (features.get(key2) === "limit" && model === "boolean") continue;
236597
+ features.set(key2, model);
236598
+ }
236599
+ for (const [key2, model] of features) {
236600
+ const line = Math.max(
236601
+ 1,
236602
+ source.slice(0, Math.max(0, source.indexOf(key2))).split(/\r?\n/).length
236603
+ );
236604
+ const fingerprint3 = sha256(
236605
+ JSON.stringify([path, key2, model, "plan_catalog"])
236606
+ );
236607
+ named.push({
236608
+ accessModel: model,
236609
+ bindingIdentityFingerprint: fingerprint3,
236610
+ bindingKind: "discovery",
236611
+ confidenceBasisPoints: 9900,
236612
+ file: path,
236613
+ fingerprint: fingerprint3,
236614
+ id: fingerprint3.slice(0, 12),
236615
+ line,
236616
+ name: displayName(key2),
236617
+ rationale: model === "limit" ? "Usage limit declared in application plans" : "Feature access declared in application plans",
236618
+ suggestedKey: key2,
236619
+ symbol: "plan_catalog",
236620
+ unit: null
236621
+ });
236622
+ }
236623
+ } catch (error51) {
236624
+ if (!(error51 instanceof PricingExtractionError)) throw error51;
236625
+ }
236626
+ return named;
236155
236627
  }
236156
236628
  async function detectFramework(cwd2, requestedRoots) {
236157
236629
  let packageJson = {};
@@ -236446,7 +236918,7 @@ async function runFeatureSetup(input) {
236446
236918
  const existingManifestSource = await readable(
236447
236919
  resolve2(input.cwd, manifestPath)
236448
236920
  );
236449
- const existingManifestValidation = existingManifestSource ? parseFeatureManifestSource(existingManifestSource) : null;
236921
+ const existingManifestValidation = existingManifestSource && !input.freshDiscovery ? parseFeatureManifestSource(existingManifestSource) : null;
236450
236922
  if (existingManifestValidation && !existingManifestValidation.ok) {
236451
236923
  throw new Error(
236452
236924
  `The existing ${manifestPath} is invalid. Run \`saasfunnels catalog validate\` and repair it before setup.`
@@ -236493,7 +236965,7 @@ async function runFeatureSetup(input) {
236493
236965
  candidates,
236494
236966
  accepted,
236495
236967
  input.mappings ?? {},
236496
- existingManifestValidation?.manifest
236968
+ input.freshDiscovery ? void 0 : existingManifestValidation?.manifest
236497
236969
  );
236498
236970
  const validation = validateFeatureCatalogManifest(manifest);
236499
236971
  const manifestContents = (0, import_yaml2.stringify)(manifest, {
@@ -236548,7 +237020,7 @@ async function runFeatureSetup(input) {
236548
237020
  (edit) => changedEdits.some((changed) => changed.id === edit.id)
236549
237021
  );
236550
237022
  changeRecordPath = ".saasfunnels/feature-installation.json";
236551
- const record4 = {
237023
+ const record3 = {
236552
237024
  appliedAt: (/* @__PURE__ */ new Date()).toISOString(),
236553
237025
  environment: input.environment,
236554
237026
  files: changedEdits.map((edit) => ({
@@ -236565,7 +237037,7 @@ async function runFeatureSetup(input) {
236565
237037
  path: change.path
236566
237038
  })),
236567
237039
  {
236568
- contents: `${JSON.stringify(record4, null, 2)}
237040
+ contents: `${JSON.stringify(record3, null, 2)}
236569
237041
  `,
236570
237042
  path: changeRecordPath
236571
237043
  }
@@ -236703,9 +237175,98 @@ Applied reviewed edits. Change record: ${result3.changeRecordPath}` : result3.id
236703
237175
  ].join("\n");
236704
237176
  }
236705
237177
 
237178
+ // src/discovery-coverage.ts
237179
+ var exec3 = promisify3(execFile3);
237180
+ async function discoverCoverageLimitations(cwd2) {
237181
+ const { stdout } = await exec3(
237182
+ "git",
237183
+ ["ls-files", "--cached", "--others", "--exclude-standard", "-z", "--", "."],
237184
+ { cwd: cwd2, maxBuffer: 32 * 1024 * 1024 }
237185
+ );
237186
+ const files = [...new Set(stdout.split("\0").filter(Boolean))].sort();
237187
+ if (files.length > 5e4)
237188
+ throw new Error(
237189
+ "Feature discovery needs attention: more than 50,000 repository files. Narrow the application repository before scanning."
237190
+ );
237191
+ const sources = /* @__PURE__ */ new Map();
237192
+ const results = /* @__PURE__ */ new Map();
237193
+ const record3 = (code, file2) => {
237194
+ const paths = results.get(code) ?? /* @__PURE__ */ new Set();
237195
+ if (paths.size < 12) paths.add(file2);
237196
+ results.set(code, paths);
237197
+ };
237198
+ for (const path of files) {
237199
+ if (path.length > 200 || path.startsWith("/") || path.includes("..") || /[\x00-\x1f]/.test(path) || sensitivePathPattern.test(path) || /secret|credential/i.test(path) || nonProductPath.test(path) || path.split("/").some(
237200
+ (part) => ignoredSegments.has(part) || /^\.next(?:[-.]|$)/.test(part)
237201
+ ))
237202
+ continue;
237203
+ const stat = await lstat2(join2(cwd2, path)).catch(() => null);
237204
+ if (!stat?.isFile() || stat.isSymbolicLink()) continue;
237205
+ if (/\.(?:py|rb|go|rs|java|kt|cs|php|ex|exs|scala|swift|vue|svelte)$/.test(
237206
+ path
237207
+ )) {
237208
+ record3("unsupported_language", path);
237209
+ continue;
237210
+ }
237211
+ if (!/\.[cm]?[jt]sx?$/.test(path) || /\.d\.ts$/.test(path) || stat.size > 2e6)
237212
+ continue;
237213
+ const source = await readFile3(join2(cwd2, path), "utf8");
237214
+ sources.set(path, source);
237215
+ const file2 = parseApplicationSource(path, source);
237216
+ const visit = (node) => {
237217
+ if (!isProductNode(node)) return;
237218
+ if ((import_typescript5.default.isVariableDeclaration(node) || import_typescript5.default.isPropertyAssignment(node)) && node.initializer) {
237219
+ const name = node.name.getText(file2).replace(/["'_-]/g, "");
237220
+ let initializer3 = node.initializer;
237221
+ while (import_typescript5.default.isAsExpression(initializer3) || import_typescript5.default.isSatisfiesExpression(initializer3) || import_typescript5.default.isParenthesizedExpression(initializer3))
237222
+ initializer3 = initializer3.expression;
237223
+ const commercialFields = (node2) => {
237224
+ if (import_typescript5.default.isPropertyAssignment(node2) && /^(?:prices?|quotas?|features?|entitlements?|.*Limit|.*Allowance|lookupKey|amount|unit_amount)$/i.test(
237225
+ node2.name.getText(file2).replace(/["']/g, "")
237226
+ ))
237227
+ return true;
237228
+ return import_typescript5.default.forEachChild(
237229
+ node2,
237230
+ (child) => commercialFields(child) ? true : void 0
237231
+ ) ?? false;
237232
+ };
237233
+ const entitlementObject = /trialfeatures|trialentitlements|externalentitlements/i.test(name) && import_typescript5.default.isObjectLiteralExpression(initializer3) && initializer3.properties.length > 0;
237234
+ if (/(?:addons?|capacitybands?|usagerates?|meteredpricing|trialfeatures|trialentitlements|externalentitlements|seatpricing)/i.test(
237235
+ name
237236
+ ) && (import_typescript5.default.isArrayLiteralExpression(initializer3) || import_typescript5.default.isObjectLiteralExpression(initializer3)) && (entitlementObject || commercialFields(initializer3)))
237237
+ record3("commercial_extensions", path);
237238
+ }
237239
+ if (import_typescript5.default.isCallExpression(node)) {
237240
+ const name = import_typescript5.default.isIdentifier(node.expression) ? node.expression.text : import_typescript5.default.isPropertyAccessExpression(node.expression) ? node.expression.name.text : "";
237241
+ if (/^(?:has|check|require|assert|enforce|evaluate|canUse|is)(?:Feature|Entitlement|Quota|UsageLimit)/i.test(
237242
+ name
237243
+ ) && !namedFeatureEvidence(path, node.getText(file2)).length)
237244
+ record3("dynamic_access", path);
237245
+ }
237246
+ import_typescript5.default.forEachChild(node, visit);
237247
+ };
237248
+ visit(file2);
237249
+ }
237250
+ const resolvePlanConstant = planConstantResolver(sources);
237251
+ for (const [path, source] of sources) {
237252
+ if (planRestrictionEvidence(path, source).some(
237253
+ (finding) => finding.reference && !resolvePlanConstant(path, finding.reference, finding.line)
237254
+ ))
237255
+ record3("dynamic_access", path);
237256
+ }
237257
+ return [...results].map(([code, paths]) => ({ code, files: [...paths] }));
237258
+ }
237259
+
237260
+ // src/setup-run.ts
237261
+ import { createHash as createHash4 } from "node:crypto";
237262
+ import { execFile as execFile4 } from "node:child_process";
237263
+ import { promisify as promisify4 } from "node:util";
237264
+ import { readFile as readFile6, writeFile as writeFile3, mkdir as mkdir3 } from "node:fs/promises";
237265
+ import { join as join5 } from "node:path";
237266
+
236706
237267
  // src/plan-sources.ts
236707
- import { readFile as readFile3, readdir as readdir2, lstat as lstat2, writeFile as writeFile2, mkdir as mkdir2 } from "node:fs/promises";
236708
- import { dirname as dirname2, extname as extname2, join as join2, relative as relative2, resolve as resolve3, sep } from "node:path";
237268
+ import { readFile as readFile4, readdir as readdir2, lstat as lstat3, writeFile as writeFile2, mkdir as mkdir2 } from "node:fs/promises";
237269
+ import { dirname as dirname2, extname as extname2, join as join3, relative as relative2, resolve as resolve3, sep } from "node:path";
236709
237270
  var planSourceApprovalPath = ".saasfunnels/plan-sources.json";
236710
237271
  var maxPlanSourceFiles = 12;
236711
237272
  var maxPlanSourceCharacters = 512e3;
@@ -236772,7 +237333,7 @@ async function discoverPlanSourceCandidates(input) {
236772
237333
  continue;
236773
237334
  let entryStat;
236774
237335
  try {
236775
- entryStat = await lstat2(current);
237336
+ entryStat = await lstat3(current);
236776
237337
  } catch {
236777
237338
  continue;
236778
237339
  }
@@ -236782,7 +237343,7 @@ async function discoverPlanSourceCandidates(input) {
236782
237343
  for (const entry of entries.sort(
236783
237344
  (a, b) => a.name.localeCompare(b.name)
236784
237345
  )) {
236785
- queue.push(join2(current, entry.name));
237346
+ queue.push(join3(current, entry.name));
236786
237347
  }
236787
237348
  continue;
236788
237349
  }
@@ -236796,7 +237357,7 @@ async function discoverPlanSourceCandidates(input) {
236796
237357
  );
236797
237358
  continue;
236798
237359
  }
236799
- const contents = await readFile3(current, "utf8");
237360
+ const contents = await readFile4(current, "utf8");
236800
237361
  const hasStripePriceId = stripePriceIdPattern.test(contents);
236801
237362
  const named = looksLikePlanSource(relativePath);
236802
237363
  const looksPriced = billingIntervalPattern.test(contents) && chargeAmountPattern.test(contents);
@@ -236819,7 +237380,7 @@ async function discoverPlanSourceCandidates(input) {
236819
237380
  }
236820
237381
  async function readApprovedPlanSources(cwd2) {
236821
237382
  try {
236822
- const raw = await readFile3(resolve3(cwd2, planSourceApprovalPath), "utf8");
237383
+ const raw = await readFile4(resolve3(cwd2, planSourceApprovalPath), "utf8");
236823
237384
  const parsed = JSON.parse(raw);
236824
237385
  return Array.isArray(parsed.files) ? parsed.files.filter(
236825
237386
  (value) => typeof value === "string"
@@ -236866,7 +237427,7 @@ async function buildPlanMappingHandoff(input) {
236866
237427
  if (!kind) {
236867
237428
  throw new Error(`${relativePath} is not a supported plan source type.`);
236868
237429
  }
236869
- const content = await readFile3(resolve3(input.cwd, relativePath), "utf8");
237430
+ const content = await readFile4(resolve3(input.cwd, relativePath), "utf8");
236870
237431
  if (content.length > maxPlanSourceCharacters) {
236871
237432
  throw new Error(
236872
237433
  `${relativePath} is ${content.length} characters; the limit is ${maxPlanSourceCharacters}.`
@@ -236882,68 +237443,12 @@ function planMappingRequestKey(input) {
236882
237443
  }
236883
237444
 
236884
237445
  // src/plan-branches.ts
236885
- import { readdir as readdir3, readFile as readFile4, lstat as lstat3 } from "node:fs/promises";
236886
- import { extname as extname3, join as join3, relative as relative3, resolve as resolve4, sep as sep2 } from "node:path";
237446
+ import { createHash as createHash3 } from "node:crypto";
237447
+ import { readdir as readdir3, readFile as readFile5, lstat as lstat4 } from "node:fs/promises";
237448
+ import { extname as extname3, join as join4, relative as relative3, resolve as resolve4, sep as sep2 } from "node:path";
236887
237449
  var maxPlanBranchFileCharacters = 2e6;
236888
237450
  var codeExtensions = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
236889
237451
  var nonDefinitionPattern2 = /(^|\/)(__tests__|__mocks__|tests?|specs?|fixtures?|testing|mocks?|mock-data|stories|__stories__)(\/)|\.(test|spec|d|stories)\.[cm]?[jt]sx?$/i;
236890
- var comparisonPattern = /\b([A-Za-z_$][\w$]*(?:\.[\w$]+)*)\s*(===|==|!==|!=)\s*(?:["'`]([A-Za-z][A-Za-z0-9_ -]{0,39})["'`]|([A-Za-z_$][\w$]*(?:\.[\w$]+){0,2}))/g;
236891
- var planIdentifierPattern = /(plan|tier|level|subscription|package)/i;
236892
- var enumOpenPattern = /\b(?:enum|const)\s+([A-Za-z_$][\w$]*)\s*(?:=\s*)?\{/;
236893
- var memberPattern = /^\s*([A-Za-z_$][\w$]*)\s*[:=]\s*["'`]([A-Za-z][A-Za-z0-9_ -]{0,39})["'`]/;
236894
- var blockClosePattern = /^\s*\}/;
236895
- var simpleConstPattern = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*(?::\s*[\w<>[\]|\s]+)?=\s*["'`]([A-Za-z][A-Za-z0-9_ -]{0,39})["'`]/;
236896
- var denialPattern = /\b(?:throw|redirect|notFound|forbidden)\b|\breturn\s+(?:null|false|undefined)\b|upgrade|paywall|locked|disabled|403/i;
236897
- var restrictionNamePattern = /\b(?:needs?|requires?|must)[A-Z_]|\b(?:is|has)?(?:Locked|Blocked|Restricted|Gated|Disabled)|upgrade|paywall/i;
236898
- var numericBranchPattern = /\?\s*[\d_]+\s*:\s*[\d_]+|:\s*[\d_]+\s*[,;)]/;
236899
- var renderPattern = /<[A-Z][\w.]*|className=|return\s*\(/;
236900
- var marketingPattern = /\b(?:upgrade|get started|contact sales|choose|current plan|most popular|per month|per year|\/mo\b|\/yr\b)|\$\{?\d/i;
236901
- var escapePattern = /\breturn\s+(?:null|false|undefined)\b|\bthrow\b|\bredirect\b|\bnotFound\b/;
236902
- function collectConstants(lines, into) {
236903
- let container = null;
236904
- for (const line of lines) {
236905
- if (container && blockClosePattern.test(line)) {
236906
- container = null;
236907
- continue;
236908
- }
236909
- if (!container) {
236910
- const open = line.match(enumOpenPattern);
236911
- if (open?.[1]) {
236912
- container = open[1];
236913
- continue;
236914
- }
236915
- const simple = line.match(simpleConstPattern);
236916
- if (simple?.[1] && simple[2]) record3(into, simple[1], simple[2]);
236917
- continue;
236918
- }
236919
- const member = line.match(memberPattern);
236920
- if (member?.[1] && member[2]) {
236921
- record3(into, `${container}.${member[1]}`, member[2]);
236922
- record3(into, member[1], member[2]);
236923
- }
236924
- }
236925
- }
236926
- function record3(into, name, value) {
236927
- const normalized = value.toLowerCase();
236928
- if (!into.has(name)) {
236929
- into.set(name, normalized);
236930
- return;
236931
- }
236932
- if (into.get(name) !== normalized) into.set(name, null);
236933
- }
236934
- function resolveConstant(index, reference) {
236935
- const direct = index.get(reference);
236936
- if (direct !== void 0) return direct;
236937
- const segments = reference.split(".");
236938
- if (segments.length > 1) {
236939
- const tail = segments.slice(-2).join(".");
236940
- const viaTail = index.get(tail);
236941
- if (viaTail !== void 0) return viaTail;
236942
- const viaMember = index.get(segments[segments.length - 1]);
236943
- if (viaMember !== void 0) return viaMember;
236944
- }
236945
- return void 0;
236946
- }
236947
237452
  function normalize2(path) {
236948
237453
  return path.split(sep2).join("/");
236949
237454
  }
@@ -236956,51 +237461,11 @@ function allowed2(relativePath, excludes) {
236956
237461
  if (nonDefinitionPattern2.test(relativePath)) return false;
236957
237462
  return !excludes.some((exclude) => relativePath.startsWith(exclude));
236958
237463
  }
236959
- function nearestSymbol2(lines, lineIndex) {
236960
- for (let index = lineIndex; index >= Math.max(0, lineIndex - 20); index -= 1) {
236961
- const match = lines[index]?.match(
236962
- /(?:export\s+)?(?:async\s+)?(?:function|class|const|let|var)\s+([A-Za-z_$][\w$]*)/
236963
- );
236964
- if (match?.[1]) return match[1];
236965
- }
236966
- return "module";
236967
- }
236968
- function assignedName(line) {
236969
- return line.match(/(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=/)?.[1] ?? null;
236970
- }
236971
- function bindingUsages(lines, lineIndex, name) {
236972
- const reference = new RegExp(`\\b${name}\\b`);
236973
- const usages = [];
236974
- lines.forEach((line, index) => {
236975
- if (index === lineIndex || !reference.test(line)) return;
236976
- usages.push(line);
236977
- });
236978
- return usages.join("\n");
236979
- }
236980
- function shapeAt(lines, lineIndex) {
236981
- const line = lines[lineIndex] ?? "";
236982
- const window = lines.slice(lineIndex, lineIndex + 4).join("\n");
236983
- if (numericBranchPattern.test(line)) return "limit";
236984
- if (renderPattern.test(window) && marketingPattern.test(window) && !escapePattern.test(window)) {
236985
- return "presentation";
236986
- }
236987
- return "boolean";
236988
- }
236989
- function polarityAt(lines, lineIndex, negated) {
236990
- const window = lines.slice(lineIndex, lineIndex + 3).join("\n");
236991
- const bound = assignedName(lines[lineIndex] ?? "");
236992
- const named = bound ? restrictionNamePattern.test(bound) : false;
236993
- const usages = bound ? bindingUsages(lines, lineIndex, bound) : "";
236994
- if (!named && !denialPattern.test(window) && !denialPattern.test(usages)) {
236995
- return "unclear";
236996
- }
236997
- return negated ? "unclear" : "deny";
236998
- }
236999
237464
  function clusterPlanBranches(branches) {
237000
237465
  const clusters = /* @__PURE__ */ new Map();
237001
237466
  for (const branch of branches) {
237002
- const segments = branch.repositoryPath.split("/");
237003
- const location = segments.slice(0, -1).join("/") || ".";
237467
+ const fullLocation = `${branch.repositoryPath}::${branch.symbol}`;
237468
+ const location = fullLocation.length <= 400 ? fullLocation : `${fullLocation.slice(0, 367)}~${createHash3("sha256").update(fullLocation).digest("hex").slice(0, 32)}`;
237004
237469
  const key2 = `${branch.shape}|${location}`;
237005
237470
  const existing = clusters.get(key2);
237006
237471
  if (existing) existing.push(branch);
@@ -237031,7 +237496,7 @@ async function discoverPlanBranches(input) {
237031
237496
  const roots = input.roots ?? [".", ...defaultRoots];
237032
237497
  const seen = /* @__PURE__ */ new Set();
237033
237498
  const branches = [];
237034
- const constants = /* @__PURE__ */ new Map();
237499
+ const sources = /* @__PURE__ */ new Map();
237035
237500
  const pending = [];
237036
237501
  const inRepository = await repositorySourceScope(input.cwd);
237037
237502
  const queue = roots.map((root) => resolve4(input.cwd, root));
@@ -237044,7 +237509,7 @@ async function discoverPlanBranches(input) {
237044
237509
  continue;
237045
237510
  let entryStat;
237046
237511
  try {
237047
- entryStat = await lstat3(current);
237512
+ entryStat = await lstat4(current);
237048
237513
  } catch {
237049
237514
  continue;
237050
237515
  }
@@ -237054,7 +237519,7 @@ async function discoverPlanBranches(input) {
237054
237519
  for (const entry of entries.sort(
237055
237520
  (a, b) => a.name.localeCompare(b.name)
237056
237521
  )) {
237057
- queue.push(join3(current, entry.name));
237522
+ queue.push(join4(current, entry.name));
237058
237523
  }
237059
237524
  continue;
237060
237525
  }
@@ -237064,30 +237529,15 @@ async function discoverPlanBranches(input) {
237064
237529
  throw new Error(
237065
237530
  "Plan discovery found a source file above the 2 MB per-file limit. Split large source files before retrying."
237066
237531
  );
237067
- const lines = (await readFile4(current, "utf8")).split(/\r?\n/);
237068
- collectConstants(lines, constants);
237069
- lines.forEach((line, lineIndex) => {
237070
- comparisonPattern.lastIndex = 0;
237071
- let match;
237072
- while (match = comparisonPattern.exec(line)) {
237073
- const [, identifier, operator, literal2, reference] = match;
237074
- if (!planIdentifierPattern.test(identifier ?? "")) continue;
237075
- if (!literal2 && !reference) continue;
237076
- pending.push({
237077
- line: lineIndex + 1,
237078
- literal: literal2 ?? null,
237079
- negated: operator.startsWith("!"),
237080
- polarity: polarityAt(lines, lineIndex, operator.startsWith("!")),
237081
- reference: reference ?? null,
237082
- repositoryPath: relativePath,
237083
- shape: shapeAt(lines, lineIndex),
237084
- symbol: nearestSymbol2(lines, lineIndex)
237085
- });
237086
- }
237087
- });
237532
+ const source = await readFile5(current, "utf8");
237533
+ sources.set(relativePath, source);
237534
+ for (const evidence of planRestrictionEvidence(relativePath, source)) {
237535
+ pending.push({ ...evidence, repositoryPath: relativePath });
237536
+ }
237088
237537
  }
237538
+ const resolveConstant = planConstantResolver(sources);
237089
237539
  for (const item of pending) {
237090
- const value = item.literal ? item.literal.toLowerCase() : resolveConstant(constants, item.reference);
237540
+ const value = item.literal ? item.literal.toLowerCase() : resolveConstant(item.repositoryPath, item.reference, item.line);
237091
237541
  if (!value || !planValues.has(value)) continue;
237092
237542
  branches.push({
237093
237543
  line: item.line,
@@ -237104,8 +237554,8 @@ async function discoverPlanBranches(input) {
237104
237554
  }
237105
237555
 
237106
237556
  // src/setup-run.ts
237107
- var exec3 = promisify3(execFile3);
237108
- var hash2 = (text) => createHash3("sha256").update(text).digest("hex");
237557
+ var exec4 = promisify4(execFile4);
237558
+ var hash2 = (text) => createHash4("sha256").update(text).digest("hex");
237109
237559
  var contextSchema = external_exports.object({
237110
237560
  workspaceId: external_exports.string(),
237111
237561
  generation: external_exports.string().regex(/^[a-f0-9]{64}$/),
@@ -237177,15 +237627,15 @@ async function runGuidedSetup(options) {
237177
237627
  "Connect Stripe and create app credentials in Setup first."
237178
237628
  );
237179
237629
  try {
237180
- await exec3("git", ["rev-parse", "HEAD"], { cwd: options.cwd });
237181
- await exec3("git", ["remote", "get-url", "origin"], { cwd: options.cwd });
237630
+ await exec4("git", ["rev-parse", "HEAD"], { cwd: options.cwd });
237631
+ await exec4("git", ["remote", "get-url", "origin"], { cwd: options.cwd });
237182
237632
  } catch {
237183
237633
  throw new Error(
237184
237634
  "Repository setup needed: run this command inside your app\u2019s Git repository with an initial commit and an origin remote. No push or production deploy is required for discovery."
237185
237635
  );
237186
237636
  }
237187
- const head = (await exec3("git", ["rev-parse", "HEAD"], { cwd: options.cwd })).stdout.trim();
237188
- const diff = (await exec3(
237637
+ const head = (await exec4("git", ["rev-parse", "HEAD"], { cwd: options.cwd })).stdout.trim();
237638
+ const diff = (await exec4(
237189
237639
  "git",
237190
237640
  [
237191
237641
  "diff",
@@ -237198,7 +237648,7 @@ async function runGuidedSetup(options) {
237198
237648
  ],
237199
237649
  { cwd: options.cwd, maxBuffer: 8e6 }
237200
237650
  )).stdout;
237201
- const untracked = (await exec3("git", ["ls-files", "--others", "--exclude-standard", "-z"], {
237651
+ const untracked = (await exec4("git", ["ls-files", "--others", "--exclude-standard", "-z"], {
237202
237652
  cwd: options.cwd
237203
237653
  })).stdout.split("\0").filter(
237204
237654
  (path) => path && !path.startsWith(".saasfunnels/") && !/(^|\/)(\.env|node_modules|dist|\.next)(\/|$|\.)/i.test(path)
@@ -237210,15 +237660,15 @@ async function runGuidedSetup(options) {
237210
237660
  const sourceHashes = await Promise.all(
237211
237661
  untracked.map(async (path) => [
237212
237662
  path,
237213
- hash2(await readFile5(join4(options.cwd, path), "utf8"))
237663
+ hash2(await readFile6(join5(options.cwd, path), "utf8"))
237214
237664
  ])
237215
237665
  );
237216
- const revision = `${head}:${hash2(JSON.stringify([diff, sourceHashes]))}`;
237217
- const remote = (await exec3("git", ["remote", "get-url", "origin"], { cwd: options.cwd })).stdout.trim();
237666
+ const revision = `${head}:${hash2(JSON.stringify(["discovery-quality-v2", diff, sourceHashes]))}`;
237667
+ const remote = (await exec4("git", ["remote", "get-url", "origin"], { cwd: options.cwd })).stdout.trim();
237218
237668
  const repositoryKey = safeRepositoryKey(remote);
237219
- const statePath = join4(options.cwd, ".saasfunnels", "setup-run.json");
237669
+ const statePath = join5(options.cwd, ".saasfunnels", "setup-run.json");
237220
237670
  if (options.resume) {
237221
- const saved = JSON.parse(await readFile5(statePath, "utf8"));
237671
+ const saved = JSON.parse(await readFile6(statePath, "utf8"));
237222
237672
  if (saved.generation !== context.generation || saved.repositoryKey !== repositoryKey || saved.revision !== revision)
237223
237673
  throw new Error(
237224
237674
  "The app connection or revision changed. Run setup again without --resume."
@@ -237241,7 +237691,7 @@ async function runGuidedSetup(options) {
237241
237691
  repositoryRevisionHash: hash2(revision)
237242
237692
  })).run;
237243
237693
  if (!run) throw new Error("Setup did not return a run.");
237244
- await mkdir3(join4(options.cwd, ".saasfunnels"), { recursive: true });
237694
+ await mkdir3(join5(options.cwd, ".saasfunnels"), { recursive: true });
237245
237695
  await writeFile3(
237246
237696
  statePath,
237247
237697
  JSON.stringify(
@@ -237276,9 +237726,14 @@ async function runGuidedSetup(options) {
237276
237726
  });
237277
237727
  return heartbeat;
237278
237728
  };
237279
- const send = (evidence) => {
237729
+ const send = (evidence, proposals) => {
237280
237730
  const currentStage = stage;
237281
- if (JSON.stringify({ runId: run.id, stage: currentStage, evidence }).length > 1e6)
237731
+ if (JSON.stringify({
237732
+ runId: run.id,
237733
+ stage: currentStage,
237734
+ evidence,
237735
+ ...proposals ? { proposals } : {}
237736
+ }).length > 1e6)
237282
237737
  throw new Error(
237283
237738
  "Feature discovery evidence exceeds the upload size limit. Review the source scope before retrying."
237284
237739
  );
@@ -237286,7 +237741,8 @@ async function runGuidedSetup(options) {
237286
237741
  const result3 = await request("/api/developer-tools/setup/evidence", {
237287
237742
  runId: run.id,
237288
237743
  stage: currentStage,
237289
- evidence
237744
+ evidence,
237745
+ ...proposals ? { proposals } : {}
237290
237746
  });
237291
237747
  if (typeof result3.sequence === "number")
237292
237748
  run.sequence = result3.sequence;
@@ -237306,6 +237762,11 @@ async function runGuidedSetup(options) {
237306
237762
  void update(progressState, progressFailure).catch(() => {
237307
237763
  });
237308
237764
  }, 3e4);
237765
+ const limitations = await discoverCoverageLimitations(options.cwd);
237766
+ if (limitations.length)
237767
+ options.progress?.(
237768
+ "Some app behavior needs manual review. Coverage details will appear with your findings in Setup."
237769
+ );
237309
237770
  options.progress?.(
237310
237771
  run.receipts.features ? "2/4 Features already submitted." : "2/4 Discovering features\u2026"
237311
237772
  );
@@ -237317,9 +237778,11 @@ async function runGuidedSetup(options) {
237317
237778
  environment: context.environment,
237318
237779
  apply: false,
237319
237780
  manifestOnly: true,
237781
+ freshDiscovery: true,
237320
237782
  accept: ["all"]
237321
237783
  });
237322
- if (!scan.coverage.complete) {
237784
+ const unsupportedOnly = scan.coverage.scannedFiles === 0 && !scan.coverage.byteLimitReached && limitations.some((l) => l.code === "unsupported_language");
237785
+ if (!scan.coverage.complete && !unsupportedOnly) {
237323
237786
  const reason = scan.coverage.byteLimitReached ? `${scan.coverage.oversizedFileCount} source file(s) exceed the 2 MB per-file limit. Split large source files before retrying.` : !scan.coverage.scannedFiles ? "No JavaScript or TypeScript app files were found in the source roots. Run from the application folder." : "More than 10,000 feature bindings were found. Review the source scope before retrying.";
237324
237787
  throw new Error(
237325
237788
  `Feature discovery needs attention: ${reason} Scanned ${scan.coverage.scannedFiles} of ${scan.coverage.matchedFiles} files. Nothing was submitted for this stage.`
@@ -237328,6 +237791,10 @@ async function runGuidedSetup(options) {
237328
237791
  options.progress?.(
237329
237792
  `Scanned ${scan.scannedFileCount} files; found ${scan.manifest.features.length} feature proposals.`
237330
237793
  );
237794
+ if (scan.manifest.features.length > 500)
237795
+ throw new Error(
237796
+ "Feature discovery needs attention: more than 500 features. Narrow the application scope before retrying; nothing was submitted."
237797
+ );
237331
237798
  if (!scan.ok)
237332
237799
  throw new Error(
237333
237800
  "Feature discovery needs attention. Run features setup to review the local findings."
@@ -237338,7 +237805,17 @@ async function runGuidedSetup(options) {
237338
237805
  repositoryKey,
237339
237806
  repositoryRevision: revision,
237340
237807
  discoveryRoots: scan.framework.roots
237341
- })
237808
+ }),
237809
+ scan.manifest.features.map((feature) => ({
237810
+ featureKey: feature.key,
237811
+ name: feature.name,
237812
+ accessModel: feature.accessModel,
237813
+ reason: feature.evidence.some((e) => e.symbol === "plan_catalog") ? "plan_catalog" : feature.accessModel === "limit" ? "usage_check" : feature.evidence.some(
237814
+ (e) => e.bindingKind === "server_enforcement"
237815
+ ) ? "access_check" : feature.evidence.some(
237816
+ (e) => e.bindingKind === "browser_presentation"
237817
+ ) ? "visibility_gate" : "denied_access"
237818
+ }))
237342
237819
  );
237343
237820
  }
237344
237821
  stage = "plans";
@@ -237373,8 +237850,8 @@ async function runGuidedSetup(options) {
237373
237850
  });
237374
237851
  let manual = null;
237375
237852
  try {
237376
- manual = await readFile5(
237377
- join4(options.cwd, ".saasfunnels/setup-pricing.json"),
237853
+ manual = await readFile6(
237854
+ join5(options.cwd, ".saasfunnels/setup-pricing.json"),
237378
237855
  "utf8"
237379
237856
  );
237380
237857
  } catch (error51) {
@@ -237387,7 +237864,7 @@ async function runGuidedSetup(options) {
237387
237864
  for (const candidate of sources) {
237388
237865
  try {
237389
237866
  const plans = extractSetupPricing(
237390
- manual ?? await readFile5(join4(options.cwd, candidate.path), "utf8"),
237867
+ manual ?? await readFile6(join5(options.cwd, candidate.path), "utf8"),
237391
237868
  candidate.kind,
237392
237869
  context.catalogPrices
237393
237870
  );
@@ -237416,7 +237893,7 @@ async function runGuidedSetup(options) {
237416
237893
  });
237417
237894
  if (issues.length) {
237418
237895
  await writeFile3(
237419
- join4(options.cwd, ".saasfunnels/setup-review.json"),
237896
+ join5(options.cwd, ".saasfunnels/setup-review.json"),
237420
237897
  JSON.stringify({ stage: "plans", issues }, null, 2) + "\n",
237421
237898
  { mode: 384 }
237422
237899
  );
@@ -237431,7 +237908,11 @@ async function runGuidedSetup(options) {
237431
237908
  options.progress?.(
237432
237909
  `Found ${byKey.size} plan proposals in ${reviewedFiles.length} pricing files.`
237433
237910
  );
237434
- await send({ plans: [...byKey.values()], reviewedFiles });
237911
+ await send({
237912
+ plans: [...byKey.values()],
237913
+ reviewedFiles,
237914
+ ...limitations.length ? { limitations } : {}
237915
+ });
237435
237916
  }
237436
237917
  stage = "branches";
237437
237918
  const planValues = [
@@ -237529,11 +238010,11 @@ async function submitApprovedSetupPlans(input) {
237529
238010
  }
237530
238011
 
237531
238012
  // src/cli.ts
237532
- import { mkdir as mkdir4, readFile as readFile6, writeFile as writeFile4 } from "node:fs/promises";
238013
+ import { mkdir as mkdir4, readFile as readFile7, writeFile as writeFile4 } from "node:fs/promises";
237533
238014
 
237534
238015
  // src/identity.ts
237535
238016
  var SAASFUNNELS_CLI_NAME = "saasfunnels";
237536
- var SAASFUNNELS_CLI_VERSION = "0.3.3";
238017
+ var SAASFUNNELS_CLI_VERSION = "0.3.4";
237537
238018
  var SAASFUNNELS_PRODUCT_NAME = "SaaSFunnels";
237538
238019
  var SAASFUNNELS_DEFAULT_API_BASE_URL = "https://app.saasfunnels.ai";
237539
238020
  var SAASFUNNELS_ENV = Object.freeze({
@@ -238031,7 +238512,7 @@ function featureCatalogMarkdown() {
238031
238512
  return [
238032
238513
  "# SaaSFunnels Feature Catalog Manifest",
238033
238514
  "",
238034
- "The CLI owns `.saasfunnels/catalog.yaml`. Discovery is local-only and Test-only; source content is never uploaded by the setup command.",
238515
+ "The local features setup command maintains `.saasfunnels/catalog.yaml`; applying generated changes is Test-only. Guided setup submits structured proposals in the connection's environment after explicit approval, without raw source. Coverage tasks and quota semantics require human review in the current Plans & pricing editor.",
238035
238516
  "",
238036
238517
  "Required top-level fields:",
238037
238518
  "- `schemaVersion: 1`",
@@ -239359,7 +239840,7 @@ function filesystem(options) {
239359
239840
  mkdir: async (path, mkdirOptions) => {
239360
239841
  await mkdir4(path, mkdirOptions);
239361
239842
  },
239362
- readFile: readFile6,
239843
+ readFile: readFile7,
239363
239844
  writeFile: writeFile4
239364
239845
  };
239365
239846
  }
@@ -239397,7 +239878,7 @@ async function readJsonFile(filePath, options) {
239397
239878
  }
239398
239879
  async function commandInit(flags, options) {
239399
239880
  const fs = filesystem(options);
239400
- const configPath = join5(cwd(options), ".saasfunnels", "config.json");
239881
+ const configPath = join6(cwd(options), ".saasfunnels", "config.json");
239401
239882
  const config2 = {
239402
239883
  api_base_url: apiBaseUrl2(options, flags),
239403
239884
  schema_version: cliSchemaVersion
@@ -239437,7 +239918,7 @@ async function commandAgentInstall(args, flags, options) {
239437
239918
  const artifacts = getDeveloperToolAgentHandoffArtifacts({ endpoint });
239438
239919
  const artifact = artifacts[target];
239439
239920
  const targetPath = flagString(flags, "path") ?? saasFunnelsPublicText(artifact.target_path);
239440
- const absoluteTarget = join5(cwd(options), targetPath);
239921
+ const absoluteTarget = join6(cwd(options), targetPath);
239441
239922
  const fs = filesystem(options);
239442
239923
  await fs.mkdir(dirname3(absoluteTarget), { recursive: true });
239443
239924
  await fs.writeFile(