saasfunnels 0.3.2 → 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);
219650
+ import { execFile as execFile3 } from "node:child_process";
219651
+ import { promisify as promisify3 } from "node:util";
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
219163
219656
  import { execFile as execFile2 } from "node:child_process";
219164
219657
  import { promisify as promisify2 } 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";
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,21 +234231,6 @@ function date4(params) {
233679
234231
  // node_modules/zod/v4/classic/external.js
233680
234232
  config(en_default());
233681
234233
 
233682
- // src/feature-setup.ts
233683
- var import_yaml2 = __toESM(require_dist(), 1);
233684
- import { createHash as createHash2, randomUUID } from "node:crypto";
233685
- import {
233686
- access,
233687
- mkdir,
233688
- readFile as readFile2,
233689
- readdir,
233690
- rename,
233691
- rm,
233692
- lstat,
233693
- writeFile
233694
- } from "node:fs/promises";
233695
- import { dirname, extname, join, relative, resolve as resolve2 } from "node:path";
233696
-
233697
234234
  // src/runtime-contracts.js
233698
234235
  import { createHash } from "node:crypto";
233699
234236
  var DIRECT_API_AGENT_HANDOFF_VERSION = "2026-06-28.1";
@@ -234379,9 +234916,9 @@ function boundedTraitValue(value) {
234379
234916
  }
234380
234917
  function pickAccountTraits(records, keys = accountTraitKeys) {
234381
234918
  const traits = {};
234382
- for (const record4 of records) {
234919
+ for (const record3 of records) {
234383
234920
  for (const key2 of keys) {
234384
- const value = boundedTraitValue(record4[key2]);
234921
+ const value = boundedTraitValue(record3[key2]);
234385
234922
  if (value !== void 0) traits[key2] = value;
234386
234923
  }
234387
234924
  }
@@ -235114,8 +235651,8 @@ function collectSemanticCandidates(payload, source) {
235114
235651
  records.push({ path: "event.properties", record: objectValue2(wrappedEvent.properties) });
235115
235652
  }
235116
235653
  return records.flatMap(
235117
- ({ path, record: record4 }) => ["semantic_type", "event_type"].flatMap((field) => {
235118
- const value = nonEmptyString(record4[field]);
235654
+ ({ path, record: record3 }) => ["semantic_type", "event_type"].flatMap((field) => {
235655
+ const value = nonEmptyString(record3[field]);
235119
235656
  return value ? [{ path: path ? `${path}.${field}` : field, value }] : [];
235120
235657
  })
235121
235658
  );
@@ -235840,6 +236377,7 @@ var featureBindingKinds = [
235840
236377
  "discovery"
235841
236378
  ];
235842
236379
  var defaultRoots = [
236380
+ ".",
235843
236381
  "app",
235844
236382
  "src",
235845
236383
  "lib",
@@ -235848,10 +236386,13 @@ var defaultRoots = [
235848
236386
  "apps",
235849
236387
  "packages",
235850
236388
  "server",
235851
- "client"
236389
+ "client",
236390
+ "config"
235852
236391
  ];
235853
236392
  var ignoredSegments = /* @__PURE__ */ new Set([
235854
236393
  ".claude",
236394
+ ".agents",
236395
+ ".codex",
235855
236396
  ".git",
235856
236397
  ".next",
235857
236398
  ".output",
@@ -235961,7 +236502,8 @@ async function exists(path) {
235961
236502
  }
235962
236503
  function allowedPath(path, excludes) {
235963
236504
  const normalized = path.replaceAll("\\", "/");
235964
- if (sensitivePathPattern.test(normalized)) return false;
236505
+ if (sensitivePathPattern.test(normalized) || nonProductPath.test(normalized))
236506
+ return false;
235965
236507
  const segments = normalized.split("/");
235966
236508
  if (segments.some(
235967
236509
  (segment) => ignoredSegments.has(segment) || /^\.next(?:[-.]|$)/.test(segment)
@@ -235973,6 +236515,7 @@ function allowedPath(path, excludes) {
235973
236515
  );
235974
236516
  }
235975
236517
  async function walkFiles(input) {
236518
+ const inRepository = await repositorySourceScope(input.cwd);
235976
236519
  const files = [];
235977
236520
  const queue = input.roots.map((root) => resolve2(input.cwd, root));
235978
236521
  const seen = /* @__PURE__ */ new Set();
@@ -235982,7 +236525,8 @@ async function walkFiles(input) {
235982
236525
  if (seen.has(current)) continue;
235983
236526
  seen.add(current);
235984
236527
  const relativePath = safeRelative(input.cwd, current);
235985
- if (!relativePath || !allowedPath(relativePath, input.excludes)) continue;
236528
+ if (relativePath === null && current !== resolve2(input.cwd) || !inRepository(relativePath ?? "") || !allowedPath(relativePath ?? "", input.excludes))
236529
+ continue;
235986
236530
  let currentStat;
235987
236531
  try {
235988
236532
  currentStat = await lstat(current);
@@ -235994,7 +236538,9 @@ async function walkFiles(input) {
235994
236538
  entries.sort((left, right) => left.name.localeCompare(right.name)).forEach((entry) => queue.push(join(current, entry.name)));
235995
236539
  continue;
235996
236540
  }
235997
- 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
+ ))) {
235998
236544
  if (currentStat.size > 2e6) {
235999
236545
  oversizedFileCount++;
236000
236546
  continue;
@@ -236004,102 +236550,80 @@ async function walkFiles(input) {
236004
236550
  }
236005
236551
  return { files: files.sort(), oversizedFileCount };
236006
236552
  }
236007
- function nearestSymbol(lines, lineIndex) {
236008
- for (let index = lineIndex; index >= Math.max(0, lineIndex - 20); index -= 1) {
236009
- const match = lines[index]?.match(
236010
- /(?:export\s+)?(?:async\s+)?(?:function|class|const|let|var)\s+([A-Za-z_$][\w$]*)/
236011
- );
236012
- if (match?.[1]) return match[1];
236013
- }
236014
- return "module";
236015
- }
236016
236553
  function candidatesFromFile(path, source) {
236017
- const lines = source.split(/\r?\n/);
236018
- const candidates = [];
236019
- const patterns = [
236020
- {
236021
- accessModel: "boolean",
236022
- confidenceBasisPoints: 9800,
236023
- pattern: /(?:hasFeature\s*\(|checkFeature\s*\(|checkEntitlement\s*\(|isFeatureEnabled\s*\()["'`]([a-z][a-z0-9_.-]{1,79})["'`]/g,
236024
- bindingKind: "server_enforcement",
236025
- rationale: "Existing server Feature or entitlement check",
236026
- unit: null
236027
- },
236028
- {
236029
- accessModel: "boolean",
236030
- bindingKind: "browser_presentation",
236031
- confidenceBasisPoints: 9600,
236032
- pattern: /<FeatureGate[^>]*featureKey\s*=\s*["'`]([a-z][a-z0-9_.-]{1,79})["'`]/g,
236033
- rationale: "Existing browser Feature presentation gate",
236034
- unit: null
236035
- },
236036
- {
236037
- accessModel: "limit",
236038
- bindingKind: "usage_reporter",
236039
- confidenceBasisPoints: 9300,
236040
- pattern: /(?:usageKey|limitKey|meterKey|featureLimit)\s*[:=]\s*["'`]([a-z][a-z0-9_.-]{1,79})["'`]/g,
236041
- rationale: "Existing usage or limit key",
236042
- unit: "uses"
236043
- },
236044
- {
236045
- accessModel: "boolean",
236046
- bindingKind: "funnel_trigger",
236047
- confidenceBasisPoints: 8900,
236048
- pattern: /(?:deniedFeatureKey|featureDenied|onFeatureDenied)\s*[:=(]\s*["'`]([a-z][a-z0-9_.-]{1,79})["'`]/g,
236049
- rationale: "Denied-access Funnel trigger",
236050
- unit: null
236051
- },
236052
- {
236053
- accessModel: "boolean",
236054
- bindingKind: "discovery",
236055
- confidenceBasisPoints: 7600,
236056
- pattern: /(?:featureKey\s*[:=]\s*|(?:FEATURES?|ENTITLEMENTS?)\s*(?:=|:)\s*(?:\{|\[)[^\n]*?)["'`]([a-z][a-z0-9_.-]{1,79})["'`]/g,
236057
- rationale: "Feature or entitlement constant",
236058
- 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
+ };
236059
236582
  }
236060
- ];
236061
- patterns.forEach((definition) => {
236062
- lines.forEach((line, lineIndex) => {
236063
- definition.pattern.lastIndex = 0;
236064
- let match;
236065
- while (match = definition.pattern.exec(line)) {
236066
- const key2 = stableKey(match[1] ?? "");
236067
- const symbol2 = nearestSymbol(lines, lineIndex);
236068
- const fingerprint3 = sha256(
236069
- JSON.stringify({
236070
- accessModel: definition.accessModel,
236071
- file: path,
236072
- key: key2,
236073
- line: lineIndex + 1,
236074
- symbol: symbol2
236075
- })
236076
- );
236077
- const bindingIdentityFingerprint = sha256(
236078
- JSON.stringify({
236079
- bindingKind: definition.bindingKind,
236080
- rationale: definition.rationale,
236081
- symbol: symbol2
236082
- })
236083
- );
236084
- candidates.push({
236085
- accessModel: definition.accessModel,
236086
- bindingIdentityFingerprint,
236087
- bindingKind: definition.bindingKind,
236088
- confidenceBasisPoints: definition.confidenceBasisPoints,
236089
- file: path,
236090
- fingerprint: fingerprint3,
236091
- id: fingerprint3.slice(0, 12),
236092
- line: lineIndex + 1,
236093
- name: displayName(key2),
236094
- rationale: definition.rationale,
236095
- suggestedKey: key2,
236096
- symbol: symbol2,
236097
- unit: definition.unit
236098
- });
236099
- }
236100
- });
236101
- });
236102
- 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;
236103
236627
  }
236104
236628
  async function detectFramework(cwd2, requestedRoots) {
236105
236629
  let packageJson = {};
@@ -236394,7 +236918,7 @@ async function runFeatureSetup(input) {
236394
236918
  const existingManifestSource = await readable(
236395
236919
  resolve2(input.cwd, manifestPath)
236396
236920
  );
236397
- const existingManifestValidation = existingManifestSource ? parseFeatureManifestSource(existingManifestSource) : null;
236921
+ const existingManifestValidation = existingManifestSource && !input.freshDiscovery ? parseFeatureManifestSource(existingManifestSource) : null;
236398
236922
  if (existingManifestValidation && !existingManifestValidation.ok) {
236399
236923
  throw new Error(
236400
236924
  `The existing ${manifestPath} is invalid. Run \`saasfunnels catalog validate\` and repair it before setup.`
@@ -236441,7 +236965,7 @@ async function runFeatureSetup(input) {
236441
236965
  candidates,
236442
236966
  accepted,
236443
236967
  input.mappings ?? {},
236444
- existingManifestValidation?.manifest
236968
+ input.freshDiscovery ? void 0 : existingManifestValidation?.manifest
236445
236969
  );
236446
236970
  const validation = validateFeatureCatalogManifest(manifest);
236447
236971
  const manifestContents = (0, import_yaml2.stringify)(manifest, {
@@ -236496,7 +237020,7 @@ async function runFeatureSetup(input) {
236496
237020
  (edit) => changedEdits.some((changed) => changed.id === edit.id)
236497
237021
  );
236498
237022
  changeRecordPath = ".saasfunnels/feature-installation.json";
236499
- const record4 = {
237023
+ const record3 = {
236500
237024
  appliedAt: (/* @__PURE__ */ new Date()).toISOString(),
236501
237025
  environment: input.environment,
236502
237026
  files: changedEdits.map((edit) => ({
@@ -236513,7 +237037,7 @@ async function runFeatureSetup(input) {
236513
237037
  path: change.path
236514
237038
  })),
236515
237039
  {
236516
- contents: `${JSON.stringify(record4, null, 2)}
237040
+ contents: `${JSON.stringify(record3, null, 2)}
236517
237041
  `,
236518
237042
  path: changeRecordPath
236519
237043
  }
@@ -236651,9 +237175,98 @@ Applied reviewed edits. Change record: ${result3.changeRecordPath}` : result3.id
236651
237175
  ].join("\n");
236652
237176
  }
236653
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
+
236654
237267
  // src/plan-sources.ts
236655
- import { readFile as readFile3, readdir as readdir2, lstat as lstat2, writeFile as writeFile2, mkdir as mkdir2 } from "node:fs/promises";
236656
- 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";
236657
237270
  var planSourceApprovalPath = ".saasfunnels/plan-sources.json";
236658
237271
  var maxPlanSourceFiles = 12;
236659
237272
  var maxPlanSourceCharacters = 512e3;
@@ -236709,16 +237322,18 @@ async function discoverPlanSourceCandidates(input) {
236709
237322
  const roots = input.roots ?? [".", "config", ...defaultRoots];
236710
237323
  const seen = /* @__PURE__ */ new Set();
236711
237324
  const candidates = [];
237325
+ const inRepository = await repositorySourceScope(input.cwd);
236712
237326
  const queue = roots.map((root) => resolve3(input.cwd, root));
236713
237327
  while (queue.length) {
236714
237328
  const current = queue.shift();
236715
237329
  if (seen.has(current)) continue;
236716
237330
  seen.add(current);
236717
237331
  const relativePath = normalize(relative2(input.cwd, current));
236718
- if (relativePath && !allowed(relativePath, excludes)) continue;
237332
+ if (!inRepository(relativePath) || relativePath && !allowed(relativePath, excludes))
237333
+ continue;
236719
237334
  let entryStat;
236720
237335
  try {
236721
- entryStat = await lstat2(current);
237336
+ entryStat = await lstat3(current);
236722
237337
  } catch {
236723
237338
  continue;
236724
237339
  }
@@ -236728,7 +237343,7 @@ async function discoverPlanSourceCandidates(input) {
236728
237343
  for (const entry of entries.sort(
236729
237344
  (a, b) => a.name.localeCompare(b.name)
236730
237345
  )) {
236731
- queue.push(join2(current, entry.name));
237346
+ queue.push(join3(current, entry.name));
236732
237347
  }
236733
237348
  continue;
236734
237349
  }
@@ -236742,7 +237357,7 @@ async function discoverPlanSourceCandidates(input) {
236742
237357
  );
236743
237358
  continue;
236744
237359
  }
236745
- const contents = await readFile3(current, "utf8");
237360
+ const contents = await readFile4(current, "utf8");
236746
237361
  const hasStripePriceId = stripePriceIdPattern.test(contents);
236747
237362
  const named = looksLikePlanSource(relativePath);
236748
237363
  const looksPriced = billingIntervalPattern.test(contents) && chargeAmountPattern.test(contents);
@@ -236765,7 +237380,7 @@ async function discoverPlanSourceCandidates(input) {
236765
237380
  }
236766
237381
  async function readApprovedPlanSources(cwd2) {
236767
237382
  try {
236768
- const raw = await readFile3(resolve3(cwd2, planSourceApprovalPath), "utf8");
237383
+ const raw = await readFile4(resolve3(cwd2, planSourceApprovalPath), "utf8");
236769
237384
  const parsed = JSON.parse(raw);
236770
237385
  return Array.isArray(parsed.files) ? parsed.files.filter(
236771
237386
  (value) => typeof value === "string"
@@ -236812,7 +237427,7 @@ async function buildPlanMappingHandoff(input) {
236812
237427
  if (!kind) {
236813
237428
  throw new Error(`${relativePath} is not a supported plan source type.`);
236814
237429
  }
236815
- const content = await readFile3(resolve3(input.cwd, relativePath), "utf8");
237430
+ const content = await readFile4(resolve3(input.cwd, relativePath), "utf8");
236816
237431
  if (content.length > maxPlanSourceCharacters) {
236817
237432
  throw new Error(
236818
237433
  `${relativePath} is ${content.length} characters; the limit is ${maxPlanSourceCharacters}.`
@@ -236828,68 +237443,12 @@ function planMappingRequestKey(input) {
236828
237443
  }
236829
237444
 
236830
237445
  // src/plan-branches.ts
236831
- import { readdir as readdir3, readFile as readFile4, lstat as lstat3 } from "node:fs/promises";
236832
- 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";
236833
237449
  var maxPlanBranchFileCharacters = 2e6;
236834
237450
  var codeExtensions = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
236835
237451
  var nonDefinitionPattern2 = /(^|\/)(__tests__|__mocks__|tests?|specs?|fixtures?|testing|mocks?|mock-data|stories|__stories__)(\/)|\.(test|spec|d|stories)\.[cm]?[jt]sx?$/i;
236836
- 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;
236837
- var planIdentifierPattern = /(plan|tier|level|subscription|package)/i;
236838
- var enumOpenPattern = /\b(?:enum|const)\s+([A-Za-z_$][\w$]*)\s*(?:=\s*)?\{/;
236839
- var memberPattern = /^\s*([A-Za-z_$][\w$]*)\s*[:=]\s*["'`]([A-Za-z][A-Za-z0-9_ -]{0,39})["'`]/;
236840
- var blockClosePattern = /^\s*\}/;
236841
- 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})["'`]/;
236842
- var denialPattern = /\b(?:throw|redirect|notFound|forbidden)\b|\breturn\s+(?:null|false|undefined)\b|upgrade|paywall|locked|disabled|403/i;
236843
- var restrictionNamePattern = /\b(?:needs?|requires?|must)[A-Z_]|\b(?:is|has)?(?:Locked|Blocked|Restricted|Gated|Disabled)|upgrade|paywall/i;
236844
- var numericBranchPattern = /\?\s*[\d_]+\s*:\s*[\d_]+|:\s*[\d_]+\s*[,;)]/;
236845
- var renderPattern = /<[A-Z][\w.]*|className=|return\s*\(/;
236846
- var marketingPattern = /\b(?:upgrade|get started|contact sales|choose|current plan|most popular|per month|per year|\/mo\b|\/yr\b)|\$\{?\d/i;
236847
- var escapePattern = /\breturn\s+(?:null|false|undefined)\b|\bthrow\b|\bredirect\b|\bnotFound\b/;
236848
- function collectConstants(lines, into) {
236849
- let container = null;
236850
- for (const line of lines) {
236851
- if (container && blockClosePattern.test(line)) {
236852
- container = null;
236853
- continue;
236854
- }
236855
- if (!container) {
236856
- const open = line.match(enumOpenPattern);
236857
- if (open?.[1]) {
236858
- container = open[1];
236859
- continue;
236860
- }
236861
- const simple = line.match(simpleConstPattern);
236862
- if (simple?.[1] && simple[2]) record3(into, simple[1], simple[2]);
236863
- continue;
236864
- }
236865
- const member = line.match(memberPattern);
236866
- if (member?.[1] && member[2]) {
236867
- record3(into, `${container}.${member[1]}`, member[2]);
236868
- record3(into, member[1], member[2]);
236869
- }
236870
- }
236871
- }
236872
- function record3(into, name, value) {
236873
- const normalized = value.toLowerCase();
236874
- if (!into.has(name)) {
236875
- into.set(name, normalized);
236876
- return;
236877
- }
236878
- if (into.get(name) !== normalized) into.set(name, null);
236879
- }
236880
- function resolveConstant(index, reference) {
236881
- const direct = index.get(reference);
236882
- if (direct !== void 0) return direct;
236883
- const segments = reference.split(".");
236884
- if (segments.length > 1) {
236885
- const tail = segments.slice(-2).join(".");
236886
- const viaTail = index.get(tail);
236887
- if (viaTail !== void 0) return viaTail;
236888
- const viaMember = index.get(segments[segments.length - 1]);
236889
- if (viaMember !== void 0) return viaMember;
236890
- }
236891
- return void 0;
236892
- }
236893
237452
  function normalize2(path) {
236894
237453
  return path.split(sep2).join("/");
236895
237454
  }
@@ -236902,51 +237461,11 @@ function allowed2(relativePath, excludes) {
236902
237461
  if (nonDefinitionPattern2.test(relativePath)) return false;
236903
237462
  return !excludes.some((exclude) => relativePath.startsWith(exclude));
236904
237463
  }
236905
- function nearestSymbol2(lines, lineIndex) {
236906
- for (let index = lineIndex; index >= Math.max(0, lineIndex - 20); index -= 1) {
236907
- const match = lines[index]?.match(
236908
- /(?:export\s+)?(?:async\s+)?(?:function|class|const|let|var)\s+([A-Za-z_$][\w$]*)/
236909
- );
236910
- if (match?.[1]) return match[1];
236911
- }
236912
- return "module";
236913
- }
236914
- function assignedName(line) {
236915
- return line.match(/(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=/)?.[1] ?? null;
236916
- }
236917
- function bindingUsages(lines, lineIndex, name) {
236918
- const reference = new RegExp(`\\b${name}\\b`);
236919
- const usages = [];
236920
- lines.forEach((line, index) => {
236921
- if (index === lineIndex || !reference.test(line)) return;
236922
- usages.push(line);
236923
- });
236924
- return usages.join("\n");
236925
- }
236926
- function shapeAt(lines, lineIndex) {
236927
- const line = lines[lineIndex] ?? "";
236928
- const window = lines.slice(lineIndex, lineIndex + 4).join("\n");
236929
- if (numericBranchPattern.test(line)) return "limit";
236930
- if (renderPattern.test(window) && marketingPattern.test(window) && !escapePattern.test(window)) {
236931
- return "presentation";
236932
- }
236933
- return "boolean";
236934
- }
236935
- function polarityAt(lines, lineIndex, negated) {
236936
- const window = lines.slice(lineIndex, lineIndex + 3).join("\n");
236937
- const bound = assignedName(lines[lineIndex] ?? "");
236938
- const named = bound ? restrictionNamePattern.test(bound) : false;
236939
- const usages = bound ? bindingUsages(lines, lineIndex, bound) : "";
236940
- if (!named && !denialPattern.test(window) && !denialPattern.test(usages)) {
236941
- return "unclear";
236942
- }
236943
- return negated ? "unclear" : "deny";
236944
- }
236945
237464
  function clusterPlanBranches(branches) {
236946
237465
  const clusters = /* @__PURE__ */ new Map();
236947
237466
  for (const branch of branches) {
236948
- const segments = branch.repositoryPath.split("/");
236949
- 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)}`;
236950
237469
  const key2 = `${branch.shape}|${location}`;
236951
237470
  const existing = clusters.get(key2);
236952
237471
  if (existing) existing.push(branch);
@@ -236977,18 +237496,20 @@ async function discoverPlanBranches(input) {
236977
237496
  const roots = input.roots ?? [".", ...defaultRoots];
236978
237497
  const seen = /* @__PURE__ */ new Set();
236979
237498
  const branches = [];
236980
- const constants = /* @__PURE__ */ new Map();
237499
+ const sources = /* @__PURE__ */ new Map();
236981
237500
  const pending = [];
237501
+ const inRepository = await repositorySourceScope(input.cwd);
236982
237502
  const queue = roots.map((root) => resolve4(input.cwd, root));
236983
237503
  while (queue.length) {
236984
237504
  const current = queue.shift();
236985
237505
  if (seen.has(current)) continue;
236986
237506
  seen.add(current);
236987
237507
  const relativePath = normalize2(relative3(input.cwd, current));
236988
- if (relativePath && !allowed2(relativePath, excludes)) continue;
237508
+ if (!inRepository(relativePath) || relativePath && !allowed2(relativePath, excludes))
237509
+ continue;
236989
237510
  let entryStat;
236990
237511
  try {
236991
- entryStat = await lstat3(current);
237512
+ entryStat = await lstat4(current);
236992
237513
  } catch {
236993
237514
  continue;
236994
237515
  }
@@ -236998,7 +237519,7 @@ async function discoverPlanBranches(input) {
236998
237519
  for (const entry of entries.sort(
236999
237520
  (a, b) => a.name.localeCompare(b.name)
237000
237521
  )) {
237001
- queue.push(join3(current, entry.name));
237522
+ queue.push(join4(current, entry.name));
237002
237523
  }
237003
237524
  continue;
237004
237525
  }
@@ -237008,30 +237529,15 @@ async function discoverPlanBranches(input) {
237008
237529
  throw new Error(
237009
237530
  "Plan discovery found a source file above the 2 MB per-file limit. Split large source files before retrying."
237010
237531
  );
237011
- const lines = (await readFile4(current, "utf8")).split(/\r?\n/);
237012
- collectConstants(lines, constants);
237013
- lines.forEach((line, lineIndex) => {
237014
- comparisonPattern.lastIndex = 0;
237015
- let match;
237016
- while (match = comparisonPattern.exec(line)) {
237017
- const [, identifier, operator, literal2, reference] = match;
237018
- if (!planIdentifierPattern.test(identifier ?? "")) continue;
237019
- if (!literal2 && !reference) continue;
237020
- pending.push({
237021
- line: lineIndex + 1,
237022
- literal: literal2 ?? null,
237023
- negated: operator.startsWith("!"),
237024
- polarity: polarityAt(lines, lineIndex, operator.startsWith("!")),
237025
- reference: reference ?? null,
237026
- repositoryPath: relativePath,
237027
- shape: shapeAt(lines, lineIndex),
237028
- symbol: nearestSymbol2(lines, lineIndex)
237029
- });
237030
- }
237031
- });
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
+ }
237032
237537
  }
237538
+ const resolveConstant = planConstantResolver(sources);
237033
237539
  for (const item of pending) {
237034
- 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);
237035
237541
  if (!value || !planValues.has(value)) continue;
237036
237542
  branches.push({
237037
237543
  line: item.line,
@@ -237048,8 +237554,8 @@ async function discoverPlanBranches(input) {
237048
237554
  }
237049
237555
 
237050
237556
  // src/setup-run.ts
237051
- var exec2 = promisify2(execFile2);
237052
- var hash2 = (text) => createHash3("sha256").update(text).digest("hex");
237557
+ var exec4 = promisify4(execFile4);
237558
+ var hash2 = (text) => createHash4("sha256").update(text).digest("hex");
237053
237559
  var contextSchema = external_exports.object({
237054
237560
  workspaceId: external_exports.string(),
237055
237561
  generation: external_exports.string().regex(/^[a-f0-9]{64}$/),
@@ -237121,15 +237627,15 @@ async function runGuidedSetup(options) {
237121
237627
  "Connect Stripe and create app credentials in Setup first."
237122
237628
  );
237123
237629
  try {
237124
- await exec2("git", ["rev-parse", "HEAD"], { cwd: options.cwd });
237125
- await exec2("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 });
237126
237632
  } catch {
237127
237633
  throw new Error(
237128
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."
237129
237635
  );
237130
237636
  }
237131
- const head = (await exec2("git", ["rev-parse", "HEAD"], { cwd: options.cwd })).stdout.trim();
237132
- const diff = (await exec2(
237637
+ const head = (await exec4("git", ["rev-parse", "HEAD"], { cwd: options.cwd })).stdout.trim();
237638
+ const diff = (await exec4(
237133
237639
  "git",
237134
237640
  [
237135
237641
  "diff",
@@ -237142,7 +237648,7 @@ async function runGuidedSetup(options) {
237142
237648
  ],
237143
237649
  { cwd: options.cwd, maxBuffer: 8e6 }
237144
237650
  )).stdout;
237145
- const untracked = (await exec2("git", ["ls-files", "--others", "--exclude-standard", "-z"], {
237651
+ const untracked = (await exec4("git", ["ls-files", "--others", "--exclude-standard", "-z"], {
237146
237652
  cwd: options.cwd
237147
237653
  })).stdout.split("\0").filter(
237148
237654
  (path) => path && !path.startsWith(".saasfunnels/") && !/(^|\/)(\.env|node_modules|dist|\.next)(\/|$|\.)/i.test(path)
@@ -237154,15 +237660,15 @@ async function runGuidedSetup(options) {
237154
237660
  const sourceHashes = await Promise.all(
237155
237661
  untracked.map(async (path) => [
237156
237662
  path,
237157
- hash2(await readFile5(join4(options.cwd, path), "utf8"))
237663
+ hash2(await readFile6(join5(options.cwd, path), "utf8"))
237158
237664
  ])
237159
237665
  );
237160
- const revision = `${head}:${hash2(JSON.stringify([diff, sourceHashes]))}`;
237161
- const remote = (await exec2("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();
237162
237668
  const repositoryKey = safeRepositoryKey(remote);
237163
- const statePath = join4(options.cwd, ".saasfunnels", "setup-run.json");
237669
+ const statePath = join5(options.cwd, ".saasfunnels", "setup-run.json");
237164
237670
  if (options.resume) {
237165
- const saved = JSON.parse(await readFile5(statePath, "utf8"));
237671
+ const saved = JSON.parse(await readFile6(statePath, "utf8"));
237166
237672
  if (saved.generation !== context.generation || saved.repositoryKey !== repositoryKey || saved.revision !== revision)
237167
237673
  throw new Error(
237168
237674
  "The app connection or revision changed. Run setup again without --resume."
@@ -237185,7 +237691,7 @@ async function runGuidedSetup(options) {
237185
237691
  repositoryRevisionHash: hash2(revision)
237186
237692
  })).run;
237187
237693
  if (!run) throw new Error("Setup did not return a run.");
237188
- await mkdir3(join4(options.cwd, ".saasfunnels"), { recursive: true });
237694
+ await mkdir3(join5(options.cwd, ".saasfunnels"), { recursive: true });
237189
237695
  await writeFile3(
237190
237696
  statePath,
237191
237697
  JSON.stringify(
@@ -237220,9 +237726,14 @@ async function runGuidedSetup(options) {
237220
237726
  });
237221
237727
  return heartbeat;
237222
237728
  };
237223
- const send = (evidence) => {
237729
+ const send = (evidence, proposals) => {
237224
237730
  const currentStage = stage;
237225
- 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)
237226
237737
  throw new Error(
237227
237738
  "Feature discovery evidence exceeds the upload size limit. Review the source scope before retrying."
237228
237739
  );
@@ -237230,7 +237741,8 @@ async function runGuidedSetup(options) {
237230
237741
  const result3 = await request("/api/developer-tools/setup/evidence", {
237231
237742
  runId: run.id,
237232
237743
  stage: currentStage,
237233
- evidence
237744
+ evidence,
237745
+ ...proposals ? { proposals } : {}
237234
237746
  });
237235
237747
  if (typeof result3.sequence === "number")
237236
237748
  run.sequence = result3.sequence;
@@ -237250,6 +237762,11 @@ async function runGuidedSetup(options) {
237250
237762
  void update(progressState, progressFailure).catch(() => {
237251
237763
  });
237252
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
+ );
237253
237770
  options.progress?.(
237254
237771
  run.receipts.features ? "2/4 Features already submitted." : "2/4 Discovering features\u2026"
237255
237772
  );
@@ -237261,9 +237778,11 @@ async function runGuidedSetup(options) {
237261
237778
  environment: context.environment,
237262
237779
  apply: false,
237263
237780
  manifestOnly: true,
237781
+ freshDiscovery: true,
237264
237782
  accept: ["all"]
237265
237783
  });
237266
- 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) {
237267
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.";
237268
237787
  throw new Error(
237269
237788
  `Feature discovery needs attention: ${reason} Scanned ${scan.coverage.scannedFiles} of ${scan.coverage.matchedFiles} files. Nothing was submitted for this stage.`
@@ -237272,6 +237791,10 @@ async function runGuidedSetup(options) {
237272
237791
  options.progress?.(
237273
237792
  `Scanned ${scan.scannedFileCount} files; found ${scan.manifest.features.length} feature proposals.`
237274
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
+ );
237275
237798
  if (!scan.ok)
237276
237799
  throw new Error(
237277
237800
  "Feature discovery needs attention. Run features setup to review the local findings."
@@ -237282,7 +237805,17 @@ async function runGuidedSetup(options) {
237282
237805
  repositoryKey,
237283
237806
  repositoryRevision: revision,
237284
237807
  discoveryRoots: scan.framework.roots
237285
- })
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
+ }))
237286
237819
  );
237287
237820
  }
237288
237821
  stage = "plans";
@@ -237317,8 +237850,8 @@ async function runGuidedSetup(options) {
237317
237850
  });
237318
237851
  let manual = null;
237319
237852
  try {
237320
- manual = await readFile5(
237321
- join4(options.cwd, ".saasfunnels/setup-pricing.json"),
237853
+ manual = await readFile6(
237854
+ join5(options.cwd, ".saasfunnels/setup-pricing.json"),
237322
237855
  "utf8"
237323
237856
  );
237324
237857
  } catch (error51) {
@@ -237331,7 +237864,7 @@ async function runGuidedSetup(options) {
237331
237864
  for (const candidate of sources) {
237332
237865
  try {
237333
237866
  const plans = extractSetupPricing(
237334
- manual ?? await readFile5(join4(options.cwd, candidate.path), "utf8"),
237867
+ manual ?? await readFile6(join5(options.cwd, candidate.path), "utf8"),
237335
237868
  candidate.kind,
237336
237869
  context.catalogPrices
237337
237870
  );
@@ -237360,7 +237893,7 @@ async function runGuidedSetup(options) {
237360
237893
  });
237361
237894
  if (issues.length) {
237362
237895
  await writeFile3(
237363
- join4(options.cwd, ".saasfunnels/setup-review.json"),
237896
+ join5(options.cwd, ".saasfunnels/setup-review.json"),
237364
237897
  JSON.stringify({ stage: "plans", issues }, null, 2) + "\n",
237365
237898
  { mode: 384 }
237366
237899
  );
@@ -237375,7 +237908,11 @@ async function runGuidedSetup(options) {
237375
237908
  options.progress?.(
237376
237909
  `Found ${byKey.size} plan proposals in ${reviewedFiles.length} pricing files.`
237377
237910
  );
237378
- await send({ plans: [...byKey.values()], reviewedFiles });
237911
+ await send({
237912
+ plans: [...byKey.values()],
237913
+ reviewedFiles,
237914
+ ...limitations.length ? { limitations } : {}
237915
+ });
237379
237916
  }
237380
237917
  stage = "branches";
237381
237918
  const planValues = [
@@ -237473,11 +238010,11 @@ async function submitApprovedSetupPlans(input) {
237473
238010
  }
237474
238011
 
237475
238012
  // src/cli.ts
237476
- 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";
237477
238014
 
237478
238015
  // src/identity.ts
237479
238016
  var SAASFUNNELS_CLI_NAME = "saasfunnels";
237480
- var SAASFUNNELS_CLI_VERSION = "0.3.2";
238017
+ var SAASFUNNELS_CLI_VERSION = "0.3.4";
237481
238018
  var SAASFUNNELS_PRODUCT_NAME = "SaaSFunnels";
237482
238019
  var SAASFUNNELS_DEFAULT_API_BASE_URL = "https://app.saasfunnels.ai";
237483
238020
  var SAASFUNNELS_ENV = Object.freeze({
@@ -237975,7 +238512,7 @@ function featureCatalogMarkdown() {
237975
238512
  return [
237976
238513
  "# SaaSFunnels Feature Catalog Manifest",
237977
238514
  "",
237978
- "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.",
237979
238516
  "",
237980
238517
  "Required top-level fields:",
237981
238518
  "- `schemaVersion: 1`",
@@ -239303,7 +239840,7 @@ function filesystem(options) {
239303
239840
  mkdir: async (path, mkdirOptions) => {
239304
239841
  await mkdir4(path, mkdirOptions);
239305
239842
  },
239306
- readFile: readFile6,
239843
+ readFile: readFile7,
239307
239844
  writeFile: writeFile4
239308
239845
  };
239309
239846
  }
@@ -239341,7 +239878,7 @@ async function readJsonFile(filePath, options) {
239341
239878
  }
239342
239879
  async function commandInit(flags, options) {
239343
239880
  const fs = filesystem(options);
239344
- const configPath = join5(cwd(options), ".saasfunnels", "config.json");
239881
+ const configPath = join6(cwd(options), ".saasfunnels", "config.json");
239345
239882
  const config2 = {
239346
239883
  api_base_url: apiBaseUrl2(options, flags),
239347
239884
  schema_version: cliSchemaVersion
@@ -239381,7 +239918,7 @@ async function commandAgentInstall(args, flags, options) {
239381
239918
  const artifacts = getDeveloperToolAgentHandoffArtifacts({ endpoint });
239382
239919
  const artifact = artifacts[target];
239383
239920
  const targetPath = flagString(flags, "path") ?? saasFunnelsPublicText(artifact.target_path);
239384
- const absoluteTarget = join5(cwd(options), targetPath);
239921
+ const absoluteTarget = join6(cwd(options), targetPath);
239385
239922
  const fs = filesystem(options);
239386
239923
  await fs.mkdir(dirname3(absoluteTarget), { recursive: true });
239387
239924
  await fs.writeFile(