saasfunnels 0.3.3 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/dist/library.js +211550 -11
- package/dist/saasfunnels.js +927 -446
- package/dist/types/feature-setup.d.ts +2 -0
- package/dist/types/identity.d.ts +1 -1
- package/dist/types/mcp.d.ts +1 -1
- package/dist/types/setup-pricing.d.ts +21 -0
- package/dist/types/source-analysis.d.ts +15 -0
- package/package.json +1 -1
package/dist/saasfunnels.js
CHANGED
|
@@ -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
|
|
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:
|
|
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
|
|
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
|
|
30476
|
-
if (
|
|
30477
|
-
const name = setParent(setTextRange(cloneNode(
|
|
30478
|
-
emitFlags |= getEmitFlags(
|
|
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
|
|
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 (
|
|
30981
|
-
destEmitNode.assignedName =
|
|
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,
|
|
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,
|
|
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,
|
|
45693
|
-
return parseCommandLineWorker(compilerOptionsDidYouMeanDiagnostics, commandLine,
|
|
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,
|
|
45776
|
-
const textOrDiagnostic = tryReadFile(fileName,
|
|
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,
|
|
45792
|
-
const textOrDiagnostic = tryReadFile(fileName,
|
|
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,
|
|
45795
|
+
function tryReadFile(fileName, readFile8) {
|
|
45796
45796
|
let text;
|
|
45797
45797
|
try {
|
|
45798
|
-
text =
|
|
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
|
|
62214
|
-
context.approximateLength +=
|
|
62213
|
+
const literalText2 = stripQuotes(symbolName2).replace(/\\./g, (s) => s.substring(1));
|
|
62214
|
+
context.approximateLength += literalText2.length + 2;
|
|
62215
62215
|
expression = factory.createStringLiteral(
|
|
62216
|
-
|
|
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
|
|
105856
|
-
return { assignedName:
|
|
105855
|
+
const assignedName2 = factory2.createStringLiteral(assignedNameText);
|
|
105856
|
+
return { assignedName: assignedName2, name };
|
|
105857
105857
|
}
|
|
105858
105858
|
if (isPropertyNameLiteral(name) || isPrivateIdentifier(name)) {
|
|
105859
|
-
const
|
|
105860
|
-
return { assignedName:
|
|
105859
|
+
const assignedName2 = factory2.createStringLiteralFromNode(name);
|
|
105860
|
+
return { assignedName: assignedName2, name };
|
|
105861
105861
|
}
|
|
105862
105862
|
if (isPropertyNameLiteral(name.expression) && !isIdentifier(name.expression)) {
|
|
105863
|
-
const
|
|
105864
|
-
return { assignedName:
|
|
105863
|
+
const assignedName2 = factory2.createStringLiteralFromNode(name.expression);
|
|
105864
|
+
return { assignedName: assignedName2, name };
|
|
105865
105865
|
}
|
|
105866
|
-
const
|
|
105867
|
-
context.hoistVariableDeclaration(
|
|
105866
|
+
const assignedName = factory2.getGeneratedNameForNode(name);
|
|
105867
|
+
context.hoistVariableDeclaration(assignedName);
|
|
105868
105868
|
const key2 = context.getEmitHelperFactory().createPropKeyHelper(name.expression);
|
|
105869
|
-
const assignment = factory2.createAssignment(
|
|
105869
|
+
const assignment = factory2.createAssignment(assignedName, key2);
|
|
105870
105870
|
const updatedName = factory2.updateComputedPropertyName(name, assignment);
|
|
105871
|
-
return { assignedName
|
|
105871
|
+
return { assignedName, name: updatedName };
|
|
105872
105872
|
}
|
|
105873
|
-
function createClassNamedEvaluationHelperBlock(context,
|
|
105873
|
+
function createClassNamedEvaluationHelperBlock(context, assignedName, thisExpression = context.factory.createThis()) {
|
|
105874
105874
|
const { factory: factory2 } = context;
|
|
105875
|
-
const expression = context.getEmitHelperFactory().createSetFunctionNameHelper(thisExpression,
|
|
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 =
|
|
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,
|
|
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,
|
|
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 =
|
|
105930
|
+
getOrCreateEmitNode(node).assignedName = assignedName;
|
|
105931
105931
|
return node;
|
|
105932
105932
|
}
|
|
105933
|
-
function finishTransformNamedEvaluation(context, expression,
|
|
105934
|
-
if (ignoreEmptyStringLiteral && isStringLiteral(
|
|
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,
|
|
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
|
|
105945
|
-
const initializer3 = finishTransformNamedEvaluation(context, node.initializer,
|
|
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
|
|
105955
|
-
const objectAssignmentInitializer = finishTransformNamedEvaluation(context, node.objectAssignmentInitializer,
|
|
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
|
|
105965
|
-
const initializer3 = finishTransformNamedEvaluation(context, node.initializer,
|
|
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
|
|
105977
|
-
const initializer3 = finishTransformNamedEvaluation(context, node.initializer,
|
|
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
|
|
105991
|
-
const initializer3 = finishTransformNamedEvaluation(context, node.initializer,
|
|
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
|
|
106003
|
-
const initializer3 = finishTransformNamedEvaluation(context, node.initializer,
|
|
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
|
|
106016
|
-
const right = finishTransformNamedEvaluation(context, node.right,
|
|
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
|
|
106027
|
-
const expression = finishTransformNamedEvaluation(context, node.expression,
|
|
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,
|
|
106034
|
+
function transformNamedEvaluation(context, node, ignoreEmptyStringLiteral, assignedName) {
|
|
106035
106035
|
switch (node.kind) {
|
|
106036
106036
|
case 304:
|
|
106037
|
-
return transformNamedEvaluationOfPropertyAssignment(context, node, ignoreEmptyStringLiteral,
|
|
106037
|
+
return transformNamedEvaluationOfPropertyAssignment(context, node, ignoreEmptyStringLiteral, assignedName);
|
|
106038
106038
|
case 305:
|
|
106039
|
-
return transformNamedEvaluationOfShorthandAssignmentProperty(context, node, ignoreEmptyStringLiteral,
|
|
106039
|
+
return transformNamedEvaluationOfShorthandAssignmentProperty(context, node, ignoreEmptyStringLiteral, assignedName);
|
|
106040
106040
|
case 261:
|
|
106041
|
-
return transformNamedEvaluationOfVariableDeclaration(context, node, ignoreEmptyStringLiteral,
|
|
106041
|
+
return transformNamedEvaluationOfVariableDeclaration(context, node, ignoreEmptyStringLiteral, assignedName);
|
|
106042
106042
|
case 170:
|
|
106043
|
-
return transformNamedEvaluationOfParameterDeclaration(context, node, ignoreEmptyStringLiteral,
|
|
106043
|
+
return transformNamedEvaluationOfParameterDeclaration(context, node, ignoreEmptyStringLiteral, assignedName);
|
|
106044
106044
|
case 209:
|
|
106045
|
-
return transformNamedEvaluationOfBindingElement(context, node, ignoreEmptyStringLiteral,
|
|
106045
|
+
return transformNamedEvaluationOfBindingElement(context, node, ignoreEmptyStringLiteral, assignedName);
|
|
106046
106046
|
case 173:
|
|
106047
|
-
return transformNamedEvaluationOfPropertyDeclaration(context, node, ignoreEmptyStringLiteral,
|
|
106047
|
+
return transformNamedEvaluationOfPropertyDeclaration(context, node, ignoreEmptyStringLiteral, assignedName);
|
|
106048
106048
|
case 227:
|
|
106049
|
-
return transformNamedEvaluationOfAssignmentExpression(context, node, ignoreEmptyStringLiteral,
|
|
106049
|
+
return transformNamedEvaluationOfAssignmentExpression(context, node, ignoreEmptyStringLiteral, assignedName);
|
|
106050
106050
|
case 278:
|
|
106051
|
-
return transformNamedEvaluationOfExportAssignment(context, node, ignoreEmptyStringLiteral,
|
|
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(
|
|
135902
|
+
function createGetSourceFile(readFile8, setParentNodes) {
|
|
135903
135903
|
return (fileName, languageVersionOrOptions, onError) => {
|
|
135904
135904
|
let text;
|
|
135905
135905
|
try {
|
|
135906
135906
|
mark("beforeIORead");
|
|
135907
|
-
text =
|
|
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
|
|
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:
|
|
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
|
|
211565
|
+
return ts6;
|
|
211566
211566
|
}, set exports(v) {
|
|
211567
|
-
|
|
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
|
|
216140
|
-
if (
|
|
216141
|
-
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
|
|
216450
|
+
const ts6 = directives.tagString(tag.tag);
|
|
216451
216451
|
const cs = directives.tagString(compat.tag);
|
|
216452
|
-
const msg = `Value may be parsed as either ${
|
|
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
|
|
218946
|
+
import { dirname as dirname3, join as join6, resolve as resolve5 } from "node:path";
|
|
218947
218947
|
|
|
218948
|
-
// src/
|
|
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 =
|
|
219133
|
+
function declarations(source, featuresOnly = false) {
|
|
219134
|
+
const file2 = import_typescript2.default.createSourceFile(
|
|
218967
219135
|
"pricing.ts",
|
|
218968
219136
|
source,
|
|
218969
|
-
|
|
219137
|
+
import_typescript2.default.ScriptTarget.Latest,
|
|
218970
219138
|
true,
|
|
218971
|
-
|
|
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 (
|
|
219145
|
+
if (import_typescript2.default.isPropertyAssignment(node) && fields.test(node.name.getText(file2).replace(/["']/g, "")))
|
|
218978
219146
|
return true;
|
|
218979
|
-
return
|
|
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 (
|
|
219153
|
+
if (import_typescript2.default.isVariableStatement(statement))
|
|
218986
219154
|
for (const declaration of statement.declarationList.declarations) {
|
|
218987
|
-
if (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
219172
|
+
if (import_typescript2.default.isStringLiteral(node) || import_typescript2.default.isNoSubstitutionTemplateLiteral(node))
|
|
219005
219173
|
return node.text;
|
|
219006
|
-
if (
|
|
219007
|
-
if (node.kind ===
|
|
219008
|
-
if (node.kind ===
|
|
219009
|
-
if (
|
|
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 (
|
|
219181
|
+
if (import_typescript2.default.isArrayLiteralExpression(node))
|
|
219014
219182
|
return node.elements.flatMap((n) => {
|
|
219015
|
-
if (!
|
|
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 (
|
|
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 (
|
|
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 (!
|
|
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 (
|
|
219209
|
+
if (import_typescript2.default.isCallExpression(node) && import_typescript2.default.isPropertyAccessExpression(node.expression)) {
|
|
219038
219210
|
const callee = node.expression;
|
|
219039
|
-
if (
|
|
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 || !
|
|
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
|
-
|
|
219112
|
-
|
|
219113
|
-
|
|
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/
|
|
219162
|
-
|
|
219351
|
+
// src/plan-analysis.ts
|
|
219352
|
+
var import_typescript3 = __toESM(require_typescript(), 1);
|
|
219353
|
+
function effect(node) {
|
|
219354
|
+
let result3 = node.kind === import_typescript3.default.SyntaxKind.FalseKeyword ? "deny" : null;
|
|
219355
|
+
const visit = (child) => {
|
|
219356
|
+
if (child !== node && (import_typescript3.default.isFunctionLike(child) || !isProductNode(child)))
|
|
219357
|
+
return;
|
|
219358
|
+
if (import_typescript3.default.isReturnStatement(child)) {
|
|
219359
|
+
if (child.expression?.kind === import_typescript3.default.SyntaxKind.FalseKeyword || child.expression?.kind === import_typescript3.default.SyntaxKind.NullKeyword)
|
|
219360
|
+
result3 = "deny";
|
|
219361
|
+
}
|
|
219362
|
+
if (import_typescript3.default.isThrowStatement(child)) {
|
|
219363
|
+
if (/upgrade|paywall|forbidden|entitlement|feature.+(?:denied|unavailable)|plan.+(?:required|does not|cannot)|quota|limit exceeded/i.test(
|
|
219364
|
+
child.expression.getText()
|
|
219365
|
+
))
|
|
219366
|
+
result3 = "deny";
|
|
219367
|
+
}
|
|
219368
|
+
if (import_typescript3.default.isCallExpression(child)) {
|
|
219369
|
+
const name = import_typescript3.default.isIdentifier(child.expression) ? child.expression.text : import_typescript3.default.isPropertyAccessExpression(child.expression) ? child.expression.name.text : "";
|
|
219370
|
+
if (/^(forbidden|denyAccess|requireUpgrade|showPaywall|denyFeatureAccess)$/i.test(
|
|
219371
|
+
name
|
|
219372
|
+
))
|
|
219373
|
+
result3 = "deny";
|
|
219374
|
+
if (/^(redirect|navigate|push|replace)$/.test(name) && child.arguments.some(
|
|
219375
|
+
(a) => /upgrade|paywall/.test(literalText(a) ?? "")
|
|
219376
|
+
))
|
|
219377
|
+
result3 = "deny";
|
|
219378
|
+
if (/^(status|sendStatus)$/.test(name) && child.arguments.some((a) => import_typescript3.default.isNumericLiteral(a) && a.text === "403"))
|
|
219379
|
+
result3 = "deny";
|
|
219380
|
+
}
|
|
219381
|
+
if (import_typescript3.default.isPropertyAssignment(child) && child.name.getText().replace(/["']/g, "") === "status" && import_typescript3.default.isNumericLiteral(child.initializer) && child.initializer.text === "403")
|
|
219382
|
+
result3 = "deny";
|
|
219383
|
+
import_typescript3.default.forEachChild(child, visit);
|
|
219384
|
+
};
|
|
219385
|
+
visit(node);
|
|
219386
|
+
return result3;
|
|
219387
|
+
}
|
|
219388
|
+
function conditionalEffect(node) {
|
|
219389
|
+
let conditional = false;
|
|
219390
|
+
const visit = (child) => {
|
|
219391
|
+
if (import_typescript3.default.isFunctionLike(child)) return;
|
|
219392
|
+
if (import_typescript3.default.isIfStatement(child) || import_typescript3.default.isConditionalExpression(child) || import_typescript3.default.isSwitchStatement(child) || import_typescript3.default.isIterationStatement(child, false))
|
|
219393
|
+
conditional = true;
|
|
219394
|
+
import_typescript3.default.forEachChild(child, visit);
|
|
219395
|
+
};
|
|
219396
|
+
visit(node);
|
|
219397
|
+
return conditional;
|
|
219398
|
+
}
|
|
219399
|
+
function planRestrictionEvidence(path, source) {
|
|
219400
|
+
if (nonProductPath.test(path)) return [];
|
|
219401
|
+
const file2 = parseApplicationSource(path, source);
|
|
219402
|
+
const results = [];
|
|
219403
|
+
function consequence(node) {
|
|
219404
|
+
const conditionPolarity = (condition, polarity) => {
|
|
219405
|
+
let cursor = condition;
|
|
219406
|
+
let inverted = false;
|
|
219407
|
+
while (import_typescript3.default.isParenthesizedExpression(cursor) || import_typescript3.default.isPrefixUnaryExpression(cursor) && cursor.operator === import_typescript3.default.SyntaxKind.ExclamationToken) {
|
|
219408
|
+
if (import_typescript3.default.isParenthesizedExpression(cursor)) cursor = cursor.expression;
|
|
219409
|
+
else {
|
|
219410
|
+
inverted = !inverted;
|
|
219411
|
+
cursor = cursor.operand;
|
|
219412
|
+
}
|
|
219413
|
+
}
|
|
219414
|
+
if (cursor !== node) return "unclear";
|
|
219415
|
+
return inverted ? polarity === "deny" ? "grant" : polarity === "grant" ? "deny" : "unclear" : polarity;
|
|
219416
|
+
};
|
|
219417
|
+
let child = node;
|
|
219418
|
+
for (let parent = node.parent; parent; child = parent, parent = parent.parent) {
|
|
219419
|
+
if (import_typescript3.default.isIfStatement(parent) && child === parent.expression) {
|
|
219420
|
+
if (effect(parent.thenStatement) === "deny")
|
|
219421
|
+
return {
|
|
219422
|
+
shape: "boolean",
|
|
219423
|
+
polarity: conditionalEffect(parent.thenStatement) ? "unclear" : conditionPolarity(parent.expression, "deny")
|
|
219424
|
+
};
|
|
219425
|
+
if (parent.elseStatement && effect(parent.elseStatement) === "deny")
|
|
219426
|
+
return {
|
|
219427
|
+
shape: "boolean",
|
|
219428
|
+
polarity: conditionalEffect(parent.elseStatement) ? "unclear" : conditionPolarity(parent.expression, "grant")
|
|
219429
|
+
};
|
|
219430
|
+
return null;
|
|
219431
|
+
}
|
|
219432
|
+
if (import_typescript3.default.isConditionalExpression(parent) && child === parent.condition) {
|
|
219433
|
+
const symbol2 = enclosingSymbol(parent);
|
|
219434
|
+
if (/limit|quota|capacity|max(?:imum)?|allowance/i.test(symbol2) && import_typescript3.default.isNumericLiteral(parent.whenTrue) && import_typescript3.default.isNumericLiteral(parent.whenFalse))
|
|
219435
|
+
return { shape: "limit", polarity: "unclear" };
|
|
219436
|
+
if (import_typescript3.default.isJsxElement(parent.whenTrue) || import_typescript3.default.isJsxSelfClosingElement(parent.whenTrue) || import_typescript3.default.isJsxElement(parent.whenFalse) || import_typescript3.default.isJsxSelfClosingElement(parent.whenFalse))
|
|
219437
|
+
return { shape: "presentation", polarity: "unclear" };
|
|
219438
|
+
if (effect(parent.whenTrue) === "deny")
|
|
219439
|
+
return {
|
|
219440
|
+
shape: "boolean",
|
|
219441
|
+
polarity: conditionPolarity(parent.condition, "deny")
|
|
219442
|
+
};
|
|
219443
|
+
if (effect(parent.whenFalse) === "deny")
|
|
219444
|
+
return {
|
|
219445
|
+
shape: "boolean",
|
|
219446
|
+
polarity: conditionPolarity(parent.condition, "grant")
|
|
219447
|
+
};
|
|
219448
|
+
return null;
|
|
219449
|
+
}
|
|
219450
|
+
if (import_typescript3.default.isVariableDeclaration(parent) && child === parent.initializer && import_typescript3.default.isIdentifier(parent.name)) {
|
|
219451
|
+
const scope = parent.parent.parent.parent;
|
|
219452
|
+
if (!scope) return null;
|
|
219453
|
+
let found = null;
|
|
219454
|
+
const search = (candidate) => {
|
|
219455
|
+
if (candidate === parent || candidate !== scope && import_typescript3.default.isFunctionLike(candidate))
|
|
219456
|
+
return;
|
|
219457
|
+
if (import_typescript3.default.isIdentifier(candidate) && candidate.text === parent.name.getText() && candidate.parent !== parent) {
|
|
219458
|
+
let ancestor = candidate.parent;
|
|
219459
|
+
while (ancestor && !import_typescript3.default.isIfStatement(ancestor) && !import_typescript3.default.isStatement(ancestor))
|
|
219460
|
+
ancestor = ancestor.parent;
|
|
219461
|
+
if (ancestor && import_typescript3.default.isIfStatement(ancestor) && effect(ancestor.thenStatement) === "deny")
|
|
219462
|
+
found = { shape: "boolean", polarity: "unclear" };
|
|
219463
|
+
}
|
|
219464
|
+
import_typescript3.default.forEachChild(candidate, search);
|
|
219465
|
+
};
|
|
219466
|
+
search(scope);
|
|
219467
|
+
return found;
|
|
219468
|
+
}
|
|
219469
|
+
if (import_typescript3.default.isStatement(parent) || import_typescript3.default.isFunctionLike(parent)) return null;
|
|
219470
|
+
}
|
|
219471
|
+
return null;
|
|
219472
|
+
}
|
|
219473
|
+
const visit = (node) => {
|
|
219474
|
+
if (!isProductNode(node)) return;
|
|
219475
|
+
if (import_typescript3.default.isBinaryExpression(node) && [
|
|
219476
|
+
import_typescript3.default.SyntaxKind.EqualsEqualsEqualsToken,
|
|
219477
|
+
import_typescript3.default.SyntaxKind.EqualsEqualsToken,
|
|
219478
|
+
import_typescript3.default.SyntaxKind.ExclamationEqualsEqualsToken,
|
|
219479
|
+
import_typescript3.default.SyntaxKind.ExclamationEqualsToken
|
|
219480
|
+
].includes(node.operatorToken.kind)) {
|
|
219481
|
+
const left = node.left.getText(file2);
|
|
219482
|
+
if (/plan|tier|subscription|package/i.test(left)) {
|
|
219483
|
+
const right = node.right;
|
|
219484
|
+
const literal2 = literalText(right);
|
|
219485
|
+
const reference = import_typescript3.default.isIdentifier(right) || import_typescript3.default.isPropertyAccessExpression(right) ? right.getText(file2) : null;
|
|
219486
|
+
const outcome = consequence(node);
|
|
219487
|
+
if (outcome && (literal2 || reference)) {
|
|
219488
|
+
const negated = node.operatorToken.kind === import_typescript3.default.SyntaxKind.ExclamationEqualsEqualsToken || node.operatorToken.kind === import_typescript3.default.SyntaxKind.ExclamationEqualsToken;
|
|
219489
|
+
results.push({
|
|
219490
|
+
...outcome,
|
|
219491
|
+
polarity: negated ? outcome.polarity === "deny" ? "grant" : outcome.polarity === "grant" ? "deny" : "unclear" : outcome.polarity,
|
|
219492
|
+
literal: literal2,
|
|
219493
|
+
reference,
|
|
219494
|
+
negated: node.operatorToken.kind === import_typescript3.default.SyntaxKind.ExclamationEqualsEqualsToken || node.operatorToken.kind === import_typescript3.default.SyntaxKind.ExclamationEqualsToken,
|
|
219495
|
+
line: file2.getLineAndCharacterOfPosition(node.getStart(file2)).line + 1,
|
|
219496
|
+
symbol: enclosingSymbol(node)
|
|
219497
|
+
});
|
|
219498
|
+
}
|
|
219499
|
+
}
|
|
219500
|
+
}
|
|
219501
|
+
import_typescript3.default.forEachChild(node, visit);
|
|
219502
|
+
};
|
|
219503
|
+
visit(file2);
|
|
219504
|
+
return results;
|
|
219505
|
+
}
|
|
219506
|
+
|
|
219507
|
+
// src/plan-constants.ts
|
|
219508
|
+
var import_typescript4 = __toESM(require_typescript(), 1);
|
|
219509
|
+
import { posix } from "node:path";
|
|
219510
|
+
function planConstantResolver(sources) {
|
|
219511
|
+
const modules = /* @__PURE__ */ new Map();
|
|
219512
|
+
for (const [path, source] of sources) {
|
|
219513
|
+
const module = {
|
|
219514
|
+
values: /* @__PURE__ */ new Map(),
|
|
219515
|
+
imports: /* @__PURE__ */ new Map(),
|
|
219516
|
+
exports: /* @__PURE__ */ new Set()
|
|
219517
|
+
};
|
|
219518
|
+
modules.set(path, module);
|
|
219519
|
+
const file2 = parseApplicationSource(path, source);
|
|
219520
|
+
const add = (name, expression, exported) => {
|
|
219521
|
+
module.values.set(name, expression);
|
|
219522
|
+
if (exported) module.exports.add(name.split(".")[0]);
|
|
219523
|
+
};
|
|
219524
|
+
for (const statement of file2.statements) {
|
|
219525
|
+
if (!isProductNode(statement)) continue;
|
|
219526
|
+
const exported = import_typescript4.default.canHaveModifiers(statement) && Boolean(
|
|
219527
|
+
import_typescript4.default.getModifiers(statement)?.some((m) => m.kind === import_typescript4.default.SyntaxKind.ExportKeyword)
|
|
219528
|
+
);
|
|
219529
|
+
if (import_typescript4.default.isImportDeclaration(statement) && import_typescript4.default.isStringLiteral(statement.moduleSpecifier) && !statement.importClause?.isTypeOnly) {
|
|
219530
|
+
const clause = statement.importClause;
|
|
219531
|
+
const source2 = statement.moduleSpecifier.text;
|
|
219532
|
+
if (clause?.name)
|
|
219533
|
+
module.imports.set(clause.name.text, { source: source2, name: "default" });
|
|
219534
|
+
const bindings = clause?.namedBindings;
|
|
219535
|
+
if (bindings && import_typescript4.default.isNamedImports(bindings))
|
|
219536
|
+
for (const element of bindings.elements) {
|
|
219537
|
+
if (!element.isTypeOnly)
|
|
219538
|
+
module.imports.set(element.name.text, {
|
|
219539
|
+
source: source2,
|
|
219540
|
+
name: element.propertyName?.text ?? element.name.text
|
|
219541
|
+
});
|
|
219542
|
+
}
|
|
219543
|
+
else if (bindings && import_typescript4.default.isNamespaceImport(bindings))
|
|
219544
|
+
module.imports.set(bindings.name.text, { source: source2, name: "" });
|
|
219545
|
+
}
|
|
219546
|
+
if (import_typescript4.default.isVariableStatement(statement))
|
|
219547
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
219548
|
+
if (!import_typescript4.default.isIdentifier(declaration.name) || !declaration.initializer || !isProductNode(declaration))
|
|
219549
|
+
continue;
|
|
219550
|
+
let expression = declaration.initializer;
|
|
219551
|
+
while (import_typescript4.default.isAsExpression(expression) || import_typescript4.default.isSatisfiesExpression(expression) || import_typescript4.default.isParenthesizedExpression(expression))
|
|
219552
|
+
expression = expression.expression;
|
|
219553
|
+
const name = declaration.name.text;
|
|
219554
|
+
add(name, expression, exported);
|
|
219555
|
+
if (import_typescript4.default.isObjectLiteralExpression(expression))
|
|
219556
|
+
for (const property of expression.properties) {
|
|
219557
|
+
if (import_typescript4.default.isPropertyAssignment(property) && !import_typescript4.default.isComputedPropertyName(property.name))
|
|
219558
|
+
add(
|
|
219559
|
+
`${name}.${property.name.getText(file2).replace(/["']/g, "")}`,
|
|
219560
|
+
property.initializer,
|
|
219561
|
+
exported
|
|
219562
|
+
);
|
|
219563
|
+
}
|
|
219564
|
+
}
|
|
219565
|
+
if (import_typescript4.default.isEnumDeclaration(statement))
|
|
219566
|
+
for (const member of statement.members) {
|
|
219567
|
+
if (member.initializer && !import_typescript4.default.isComputedPropertyName(member.name))
|
|
219568
|
+
add(
|
|
219569
|
+
`${statement.name.text}.${member.name.getText(file2).replace(/["']/g, "")}`,
|
|
219570
|
+
member.initializer,
|
|
219571
|
+
exported
|
|
219572
|
+
);
|
|
219573
|
+
}
|
|
219574
|
+
if (import_typescript4.default.isExportAssignment(statement))
|
|
219575
|
+
add("default", statement.expression, true);
|
|
219576
|
+
}
|
|
219577
|
+
}
|
|
219578
|
+
const resolve6 = (path, reference, depth = 0) => {
|
|
219579
|
+
if (depth > 12) return null;
|
|
219580
|
+
const module = modules.get(path);
|
|
219581
|
+
if (!module) return null;
|
|
219582
|
+
const value = module.values.get(reference);
|
|
219583
|
+
if (value) {
|
|
219584
|
+
const literal2 = literalText(value);
|
|
219585
|
+
if (literal2 !== null) return literal2.toLowerCase();
|
|
219586
|
+
if (import_typescript4.default.isIdentifier(value) || import_typescript4.default.isPropertyAccessExpression(value))
|
|
219587
|
+
return resolve6(path, value.getText(), depth + 1);
|
|
219588
|
+
return null;
|
|
219589
|
+
}
|
|
219590
|
+
const [first, ...tail] = reference.split(".");
|
|
219591
|
+
const imported = module.imports.get(first);
|
|
219592
|
+
if (!imported?.source.startsWith(".")) return null;
|
|
219593
|
+
const base = posix.normalize(
|
|
219594
|
+
posix.join(posix.dirname(path), imported.source)
|
|
219595
|
+
);
|
|
219596
|
+
if (base.startsWith("../")) return null;
|
|
219597
|
+
const stem = base.replace(/\.[cm]?jsx?$/, "");
|
|
219598
|
+
const target = [
|
|
219599
|
+
base,
|
|
219600
|
+
...[
|
|
219601
|
+
".ts",
|
|
219602
|
+
".tsx",
|
|
219603
|
+
".js",
|
|
219604
|
+
".jsx",
|
|
219605
|
+
".mjs",
|
|
219606
|
+
".cjs",
|
|
219607
|
+
"/index.ts",
|
|
219608
|
+
"/index.js"
|
|
219609
|
+
].map((ext) => stem + ext)
|
|
219610
|
+
].find((candidate) => modules.has(candidate));
|
|
219611
|
+
if (!target) return null;
|
|
219612
|
+
const member = [imported.name, ...tail].filter(Boolean).join(".");
|
|
219613
|
+
if (!modules.get(target).exports.has(member.split(".")[0])) return null;
|
|
219614
|
+
return resolve6(target, member, depth + 1);
|
|
219615
|
+
};
|
|
219616
|
+
return (path, reference, line) => {
|
|
219617
|
+
if (line !== void 0) {
|
|
219618
|
+
const file2 = parseApplicationSource(path, sources.get(path) ?? "");
|
|
219619
|
+
const root = reference.split(".")[0];
|
|
219620
|
+
let shadowed = false;
|
|
219621
|
+
const binds = (name) => import_typescript4.default.isIdentifier(name) ? name.text === root : name.elements.some(
|
|
219622
|
+
(element) => import_typescript4.default.isBindingElement(element) && binds(element.name)
|
|
219623
|
+
);
|
|
219624
|
+
const containsLine = (node) => file2.getLineAndCharacterOfPosition(node.getStart(file2)).line + 1 <= line && file2.getLineAndCharacterOfPosition(node.end).line + 1 >= line;
|
|
219625
|
+
const visit = (node) => {
|
|
219626
|
+
if (!containsLine(node)) return;
|
|
219627
|
+
if (import_typescript4.default.isFunctionLike(node) && node.parameters.some((p) => binds(p.name)))
|
|
219628
|
+
shadowed = true;
|
|
219629
|
+
if (import_typescript4.default.isCatchClause(node) && node.variableDeclaration && binds(node.variableDeclaration.name))
|
|
219630
|
+
shadowed = true;
|
|
219631
|
+
if (import_typescript4.default.isBlock(node)) {
|
|
219632
|
+
for (const statement of node.statements) {
|
|
219633
|
+
if (import_typescript4.default.isVariableStatement(statement) && statement.declarationList.declarations.some((d) => binds(d.name)))
|
|
219634
|
+
shadowed = true;
|
|
219635
|
+
if ((import_typescript4.default.isFunctionDeclaration(statement) || import_typescript4.default.isClassDeclaration(statement)) && statement.name?.text === root)
|
|
219636
|
+
shadowed = true;
|
|
219637
|
+
}
|
|
219638
|
+
}
|
|
219639
|
+
import_typescript4.default.forEachChild(node, visit);
|
|
219640
|
+
};
|
|
219641
|
+
visit(file2);
|
|
219642
|
+
if (shadowed) return null;
|
|
219643
|
+
}
|
|
219644
|
+
return resolve6(path, reference);
|
|
219645
|
+
};
|
|
219646
|
+
}
|
|
219647
|
+
|
|
219648
|
+
// src/discovery-coverage.ts
|
|
219649
|
+
var import_typescript5 = __toESM(require_typescript(), 1);
|
|
219163
219650
|
import { execFile as execFile3 } from "node:child_process";
|
|
219164
219651
|
import { promisify as promisify3 } from "node:util";
|
|
219165
|
-
import {
|
|
219166
|
-
import { join as
|
|
219652
|
+
import { lstat as lstat2, readFile as readFile3 } from "node:fs/promises";
|
|
219653
|
+
import { join as join2 } from "node:path";
|
|
219654
|
+
|
|
219655
|
+
// src/source-scope.ts
|
|
219656
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
219657
|
+
import { promisify as promisify2 } from "node:util";
|
|
219658
|
+
var exec2 = promisify2(execFile2);
|
|
219659
|
+
async function repositorySourceScope(cwd2) {
|
|
219660
|
+
try {
|
|
219661
|
+
await exec2("git", ["rev-parse", "--is-inside-work-tree"], { cwd: cwd2 });
|
|
219662
|
+
} catch (error51) {
|
|
219663
|
+
const failure = error51;
|
|
219664
|
+
if (failure.code === "ENOENT" || failure.stderr?.includes("not a git repository"))
|
|
219665
|
+
return (_path) => true;
|
|
219666
|
+
throw new Error(
|
|
219667
|
+
"Cannot read repository source scope. Check Git access and retry."
|
|
219668
|
+
);
|
|
219669
|
+
}
|
|
219670
|
+
let stdout;
|
|
219671
|
+
try {
|
|
219672
|
+
({ stdout } = await exec2(
|
|
219673
|
+
"git",
|
|
219674
|
+
[
|
|
219675
|
+
"ls-files",
|
|
219676
|
+
"--cached",
|
|
219677
|
+
"--others",
|
|
219678
|
+
"--exclude-standard",
|
|
219679
|
+
"-z",
|
|
219680
|
+
"--",
|
|
219681
|
+
"."
|
|
219682
|
+
],
|
|
219683
|
+
{
|
|
219684
|
+
cwd: cwd2,
|
|
219685
|
+
maxBuffer: 32 * 1024 * 1024
|
|
219686
|
+
}
|
|
219687
|
+
));
|
|
219688
|
+
} catch {
|
|
219689
|
+
throw new Error(
|
|
219690
|
+
"Cannot list repository sources. Check Git access and retry."
|
|
219691
|
+
);
|
|
219692
|
+
}
|
|
219693
|
+
const included = /* @__PURE__ */ new Set([""]);
|
|
219694
|
+
for (const path of stdout.split("\0").filter(Boolean)) {
|
|
219695
|
+
included.add(path);
|
|
219696
|
+
let end = path.lastIndexOf("/");
|
|
219697
|
+
while (end > 0) {
|
|
219698
|
+
included.add(path.slice(0, end));
|
|
219699
|
+
end = path.lastIndexOf("/", end - 1);
|
|
219700
|
+
}
|
|
219701
|
+
}
|
|
219702
|
+
return (path) => included.has(path);
|
|
219703
|
+
}
|
|
219704
|
+
|
|
219705
|
+
// src/feature-setup.ts
|
|
219706
|
+
var import_yaml2 = __toESM(require_dist(), 1);
|
|
219707
|
+
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
219708
|
+
import {
|
|
219709
|
+
access,
|
|
219710
|
+
mkdir,
|
|
219711
|
+
readFile as readFile2,
|
|
219712
|
+
readdir,
|
|
219713
|
+
rename,
|
|
219714
|
+
rm,
|
|
219715
|
+
lstat,
|
|
219716
|
+
writeFile
|
|
219717
|
+
} from "node:fs/promises";
|
|
219718
|
+
import { dirname, extname, join, relative, resolve as resolve2 } from "node:path";
|
|
219167
219719
|
|
|
219168
219720
|
// node_modules/zod/v4/classic/external.js
|
|
219169
219721
|
var external_exports = {};
|
|
@@ -233679,71 +234231,6 @@ function date4(params) {
|
|
|
233679
234231
|
// node_modules/zod/v4/classic/external.js
|
|
233680
234232
|
config(en_default());
|
|
233681
234233
|
|
|
233682
|
-
// src/source-scope.ts
|
|
233683
|
-
import { execFile as execFile2 } from "node:child_process";
|
|
233684
|
-
import { promisify as promisify2 } from "node:util";
|
|
233685
|
-
var exec2 = promisify2(execFile2);
|
|
233686
|
-
async function repositorySourceScope(cwd2) {
|
|
233687
|
-
try {
|
|
233688
|
-
await exec2("git", ["rev-parse", "--is-inside-work-tree"], { cwd: cwd2 });
|
|
233689
|
-
} catch (error51) {
|
|
233690
|
-
const failure = error51;
|
|
233691
|
-
if (failure.code === "ENOENT" || failure.stderr?.includes("not a git repository"))
|
|
233692
|
-
return (_path) => true;
|
|
233693
|
-
throw new Error(
|
|
233694
|
-
"Cannot read repository source scope. Check Git access and retry."
|
|
233695
|
-
);
|
|
233696
|
-
}
|
|
233697
|
-
let stdout;
|
|
233698
|
-
try {
|
|
233699
|
-
({ stdout } = await exec2(
|
|
233700
|
-
"git",
|
|
233701
|
-
[
|
|
233702
|
-
"ls-files",
|
|
233703
|
-
"--cached",
|
|
233704
|
-
"--others",
|
|
233705
|
-
"--exclude-standard",
|
|
233706
|
-
"-z",
|
|
233707
|
-
"--",
|
|
233708
|
-
"."
|
|
233709
|
-
],
|
|
233710
|
-
{
|
|
233711
|
-
cwd: cwd2,
|
|
233712
|
-
maxBuffer: 32 * 1024 * 1024
|
|
233713
|
-
}
|
|
233714
|
-
));
|
|
233715
|
-
} catch {
|
|
233716
|
-
throw new Error(
|
|
233717
|
-
"Cannot list repository sources. Check Git access and retry."
|
|
233718
|
-
);
|
|
233719
|
-
}
|
|
233720
|
-
const included = /* @__PURE__ */ new Set([""]);
|
|
233721
|
-
for (const path of stdout.split("\0").filter(Boolean)) {
|
|
233722
|
-
included.add(path);
|
|
233723
|
-
let end = path.lastIndexOf("/");
|
|
233724
|
-
while (end > 0) {
|
|
233725
|
-
included.add(path.slice(0, end));
|
|
233726
|
-
end = path.lastIndexOf("/", end - 1);
|
|
233727
|
-
}
|
|
233728
|
-
}
|
|
233729
|
-
return (path) => included.has(path);
|
|
233730
|
-
}
|
|
233731
|
-
|
|
233732
|
-
// src/feature-setup.ts
|
|
233733
|
-
var import_yaml2 = __toESM(require_dist(), 1);
|
|
233734
|
-
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
233735
|
-
import {
|
|
233736
|
-
access,
|
|
233737
|
-
mkdir,
|
|
233738
|
-
readFile as readFile2,
|
|
233739
|
-
readdir,
|
|
233740
|
-
rename,
|
|
233741
|
-
rm,
|
|
233742
|
-
lstat,
|
|
233743
|
-
writeFile
|
|
233744
|
-
} from "node:fs/promises";
|
|
233745
|
-
import { dirname, extname, join, relative, resolve as resolve2 } from "node:path";
|
|
233746
|
-
|
|
233747
234234
|
// src/runtime-contracts.js
|
|
233748
234235
|
import { createHash } from "node:crypto";
|
|
233749
234236
|
var DIRECT_API_AGENT_HANDOFF_VERSION = "2026-06-28.1";
|
|
@@ -234429,9 +234916,9 @@ function boundedTraitValue(value) {
|
|
|
234429
234916
|
}
|
|
234430
234917
|
function pickAccountTraits(records, keys = accountTraitKeys) {
|
|
234431
234918
|
const traits = {};
|
|
234432
|
-
for (const
|
|
234919
|
+
for (const record3 of records) {
|
|
234433
234920
|
for (const key2 of keys) {
|
|
234434
|
-
const value = boundedTraitValue(
|
|
234921
|
+
const value = boundedTraitValue(record3[key2]);
|
|
234435
234922
|
if (value !== void 0) traits[key2] = value;
|
|
234436
234923
|
}
|
|
234437
234924
|
}
|
|
@@ -235164,8 +235651,8 @@ function collectSemanticCandidates(payload, source) {
|
|
|
235164
235651
|
records.push({ path: "event.properties", record: objectValue2(wrappedEvent.properties) });
|
|
235165
235652
|
}
|
|
235166
235653
|
return records.flatMap(
|
|
235167
|
-
({ path, record:
|
|
235168
|
-
const value = nonEmptyString(
|
|
235654
|
+
({ path, record: record3 }) => ["semantic_type", "event_type"].flatMap((field) => {
|
|
235655
|
+
const value = nonEmptyString(record3[field]);
|
|
235169
235656
|
return value ? [{ path: path ? `${path}.${field}` : field, value }] : [];
|
|
235170
235657
|
})
|
|
235171
235658
|
);
|
|
@@ -235890,6 +236377,7 @@ var featureBindingKinds = [
|
|
|
235890
236377
|
"discovery"
|
|
235891
236378
|
];
|
|
235892
236379
|
var defaultRoots = [
|
|
236380
|
+
".",
|
|
235893
236381
|
"app",
|
|
235894
236382
|
"src",
|
|
235895
236383
|
"lib",
|
|
@@ -235898,10 +236386,13 @@ var defaultRoots = [
|
|
|
235898
236386
|
"apps",
|
|
235899
236387
|
"packages",
|
|
235900
236388
|
"server",
|
|
235901
|
-
"client"
|
|
236389
|
+
"client",
|
|
236390
|
+
"config"
|
|
235902
236391
|
];
|
|
235903
236392
|
var ignoredSegments = /* @__PURE__ */ new Set([
|
|
235904
236393
|
".claude",
|
|
236394
|
+
".agents",
|
|
236395
|
+
".codex",
|
|
235905
236396
|
".git",
|
|
235906
236397
|
".next",
|
|
235907
236398
|
".output",
|
|
@@ -236011,7 +236502,8 @@ async function exists(path) {
|
|
|
236011
236502
|
}
|
|
236012
236503
|
function allowedPath(path, excludes) {
|
|
236013
236504
|
const normalized = path.replaceAll("\\", "/");
|
|
236014
|
-
if (sensitivePathPattern.test(normalized)
|
|
236505
|
+
if (sensitivePathPattern.test(normalized) || nonProductPath.test(normalized))
|
|
236506
|
+
return false;
|
|
236015
236507
|
const segments = normalized.split("/");
|
|
236016
236508
|
if (segments.some(
|
|
236017
236509
|
(segment) => ignoredSegments.has(segment) || /^\.next(?:[-.]|$)/.test(segment)
|
|
@@ -236033,7 +236525,7 @@ async function walkFiles(input) {
|
|
|
236033
236525
|
if (seen.has(current)) continue;
|
|
236034
236526
|
seen.add(current);
|
|
236035
236527
|
const relativePath = safeRelative(input.cwd, current);
|
|
236036
|
-
if (
|
|
236528
|
+
if (relativePath === null && current !== resolve2(input.cwd) || !inRepository(relativePath ?? "") || !allowedPath(relativePath ?? "", input.excludes))
|
|
236037
236529
|
continue;
|
|
236038
236530
|
let currentStat;
|
|
236039
236531
|
try {
|
|
@@ -236046,7 +236538,9 @@ async function walkFiles(input) {
|
|
|
236046
236538
|
entries.sort((left, right) => left.name.localeCompare(right.name)).forEach((entry) => queue.push(join(current, entry.name)));
|
|
236047
236539
|
continue;
|
|
236048
236540
|
}
|
|
236049
|
-
if (currentStat.isFile() && supportedExtensions.has(extname(current)))
|
|
236541
|
+
if (currentStat.isFile() && (supportedExtensions.has(extname(current)) || /\.(json|ya?ml)$/.test(current) && /(?:^|[\/._-])(plans?|pricing|entitlements?|catalog|tiers?|features|quotas)(?:[._-]|$)/i.test(
|
|
236542
|
+
relativePath ?? ""
|
|
236543
|
+
))) {
|
|
236050
236544
|
if (currentStat.size > 2e6) {
|
|
236051
236545
|
oversizedFileCount++;
|
|
236052
236546
|
continue;
|
|
@@ -236056,102 +236550,80 @@ async function walkFiles(input) {
|
|
|
236056
236550
|
}
|
|
236057
236551
|
return { files: files.sort(), oversizedFileCount };
|
|
236058
236552
|
}
|
|
236059
|
-
function nearestSymbol(lines, lineIndex) {
|
|
236060
|
-
for (let index = lineIndex; index >= Math.max(0, lineIndex - 20); index -= 1) {
|
|
236061
|
-
const match = lines[index]?.match(
|
|
236062
|
-
/(?:export\s+)?(?:async\s+)?(?:function|class|const|let|var)\s+([A-Za-z_$][\w$]*)/
|
|
236063
|
-
);
|
|
236064
|
-
if (match?.[1]) return match[1];
|
|
236065
|
-
}
|
|
236066
|
-
return "module";
|
|
236067
|
-
}
|
|
236068
236553
|
function candidatesFromFile(path, source) {
|
|
236069
|
-
const
|
|
236070
|
-
|
|
236071
|
-
|
|
236072
|
-
|
|
236073
|
-
|
|
236074
|
-
|
|
236075
|
-
|
|
236076
|
-
|
|
236077
|
-
|
|
236078
|
-
|
|
236079
|
-
|
|
236080
|
-
|
|
236081
|
-
|
|
236082
|
-
|
|
236083
|
-
|
|
236084
|
-
|
|
236085
|
-
|
|
236086
|
-
|
|
236087
|
-
|
|
236088
|
-
|
|
236089
|
-
|
|
236090
|
-
|
|
236091
|
-
|
|
236092
|
-
|
|
236093
|
-
|
|
236094
|
-
|
|
236095
|
-
|
|
236096
|
-
|
|
236097
|
-
accessModel: "boolean",
|
|
236098
|
-
bindingKind: "funnel_trigger",
|
|
236099
|
-
confidenceBasisPoints: 8900,
|
|
236100
|
-
pattern: /(?:deniedFeatureKey|featureDenied|onFeatureDenied)\s*[:=(]\s*["'`]([a-z][a-z0-9_.-]{1,79})["'`]/g,
|
|
236101
|
-
rationale: "Denied-access Funnel trigger",
|
|
236102
|
-
unit: null
|
|
236103
|
-
},
|
|
236104
|
-
{
|
|
236105
|
-
accessModel: "boolean",
|
|
236106
|
-
bindingKind: "discovery",
|
|
236107
|
-
confidenceBasisPoints: 7600,
|
|
236108
|
-
pattern: /(?:featureKey\s*[:=]\s*|(?:FEATURES?|ENTITLEMENTS?)\s*(?:=|:)\s*(?:\{|\[)[^\n]*?)["'`]([a-z][a-z0-9_.-]{1,79})["'`]/g,
|
|
236109
|
-
rationale: "Feature or entitlement constant",
|
|
236110
|
-
unit: null
|
|
236554
|
+
const named = namedFeatureEvidence(path, source).map(
|
|
236555
|
+
(evidence) => {
|
|
236556
|
+
const fingerprint3 = sha256(
|
|
236557
|
+
JSON.stringify([
|
|
236558
|
+
path,
|
|
236559
|
+
evidence.key,
|
|
236560
|
+
evidence.model,
|
|
236561
|
+
evidence.line,
|
|
236562
|
+
evidence.symbol
|
|
236563
|
+
])
|
|
236564
|
+
);
|
|
236565
|
+
return {
|
|
236566
|
+
accessModel: evidence.model,
|
|
236567
|
+
bindingIdentityFingerprint: sha256(
|
|
236568
|
+
JSON.stringify([evidence.kind, evidence.key, evidence.symbol])
|
|
236569
|
+
),
|
|
236570
|
+
bindingKind: evidence.kind,
|
|
236571
|
+
confidenceBasisPoints: evidence.kind === "server_enforcement" ? 9800 : 9e3,
|
|
236572
|
+
file: path,
|
|
236573
|
+
fingerprint: fingerprint3,
|
|
236574
|
+
id: fingerprint3.slice(0, 12),
|
|
236575
|
+
line: evidence.line,
|
|
236576
|
+
name: displayName(evidence.key),
|
|
236577
|
+
rationale: evidence.reason,
|
|
236578
|
+
suggestedKey: evidence.key,
|
|
236579
|
+
symbol: evidence.symbol,
|
|
236580
|
+
unit: null
|
|
236581
|
+
};
|
|
236111
236582
|
}
|
|
236112
|
-
|
|
236113
|
-
|
|
236114
|
-
|
|
236115
|
-
|
|
236116
|
-
|
|
236117
|
-
|
|
236118
|
-
|
|
236119
|
-
|
|
236120
|
-
|
|
236121
|
-
|
|
236122
|
-
|
|
236123
|
-
|
|
236124
|
-
|
|
236125
|
-
|
|
236126
|
-
|
|
236127
|
-
|
|
236128
|
-
|
|
236129
|
-
|
|
236130
|
-
|
|
236131
|
-
|
|
236132
|
-
|
|
236133
|
-
|
|
236134
|
-
|
|
236135
|
-
|
|
236136
|
-
|
|
236137
|
-
|
|
236138
|
-
|
|
236139
|
-
|
|
236140
|
-
|
|
236141
|
-
|
|
236142
|
-
|
|
236143
|
-
|
|
236144
|
-
|
|
236145
|
-
|
|
236146
|
-
|
|
236147
|
-
|
|
236148
|
-
|
|
236149
|
-
|
|
236150
|
-
|
|
236151
|
-
|
|
236152
|
-
|
|
236153
|
-
|
|
236154
|
-
|
|
236583
|
+
);
|
|
236584
|
+
if (nonProductPath.test(path)) return named;
|
|
236585
|
+
try {
|
|
236586
|
+
const plans = extractSetupPricing(
|
|
236587
|
+
source,
|
|
236588
|
+
/\.json$/.test(path) ? "json" : /\.ya?ml$/.test(path) ? "yaml" : "typescript",
|
|
236589
|
+
[],
|
|
236590
|
+
{ featuresOnly: true }
|
|
236591
|
+
);
|
|
236592
|
+
const features = /* @__PURE__ */ new Map();
|
|
236593
|
+
for (const plan of plans)
|
|
236594
|
+
for (const [key2, value] of Object.entries(plan.features)) {
|
|
236595
|
+
const model = typeof value === "boolean" ? "boolean" : "limit";
|
|
236596
|
+
if (features.get(key2) === "limit" && model === "boolean") continue;
|
|
236597
|
+
features.set(key2, model);
|
|
236598
|
+
}
|
|
236599
|
+
for (const [key2, model] of features) {
|
|
236600
|
+
const line = Math.max(
|
|
236601
|
+
1,
|
|
236602
|
+
source.slice(0, Math.max(0, source.indexOf(key2))).split(/\r?\n/).length
|
|
236603
|
+
);
|
|
236604
|
+
const fingerprint3 = sha256(
|
|
236605
|
+
JSON.stringify([path, key2, model, "plan_catalog"])
|
|
236606
|
+
);
|
|
236607
|
+
named.push({
|
|
236608
|
+
accessModel: model,
|
|
236609
|
+
bindingIdentityFingerprint: fingerprint3,
|
|
236610
|
+
bindingKind: "discovery",
|
|
236611
|
+
confidenceBasisPoints: 9900,
|
|
236612
|
+
file: path,
|
|
236613
|
+
fingerprint: fingerprint3,
|
|
236614
|
+
id: fingerprint3.slice(0, 12),
|
|
236615
|
+
line,
|
|
236616
|
+
name: displayName(key2),
|
|
236617
|
+
rationale: model === "limit" ? "Usage limit declared in application plans" : "Feature access declared in application plans",
|
|
236618
|
+
suggestedKey: key2,
|
|
236619
|
+
symbol: "plan_catalog",
|
|
236620
|
+
unit: null
|
|
236621
|
+
});
|
|
236622
|
+
}
|
|
236623
|
+
} catch (error51) {
|
|
236624
|
+
if (!(error51 instanceof PricingExtractionError)) throw error51;
|
|
236625
|
+
}
|
|
236626
|
+
return named;
|
|
236155
236627
|
}
|
|
236156
236628
|
async function detectFramework(cwd2, requestedRoots) {
|
|
236157
236629
|
let packageJson = {};
|
|
@@ -236446,7 +236918,7 @@ async function runFeatureSetup(input) {
|
|
|
236446
236918
|
const existingManifestSource = await readable(
|
|
236447
236919
|
resolve2(input.cwd, manifestPath)
|
|
236448
236920
|
);
|
|
236449
|
-
const existingManifestValidation = existingManifestSource ? parseFeatureManifestSource(existingManifestSource) : null;
|
|
236921
|
+
const existingManifestValidation = existingManifestSource && !input.freshDiscovery ? parseFeatureManifestSource(existingManifestSource) : null;
|
|
236450
236922
|
if (existingManifestValidation && !existingManifestValidation.ok) {
|
|
236451
236923
|
throw new Error(
|
|
236452
236924
|
`The existing ${manifestPath} is invalid. Run \`saasfunnels catalog validate\` and repair it before setup.`
|
|
@@ -236493,7 +236965,7 @@ async function runFeatureSetup(input) {
|
|
|
236493
236965
|
candidates,
|
|
236494
236966
|
accepted,
|
|
236495
236967
|
input.mappings ?? {},
|
|
236496
|
-
existingManifestValidation?.manifest
|
|
236968
|
+
input.freshDiscovery ? void 0 : existingManifestValidation?.manifest
|
|
236497
236969
|
);
|
|
236498
236970
|
const validation = validateFeatureCatalogManifest(manifest);
|
|
236499
236971
|
const manifestContents = (0, import_yaml2.stringify)(manifest, {
|
|
@@ -236548,7 +237020,7 @@ async function runFeatureSetup(input) {
|
|
|
236548
237020
|
(edit) => changedEdits.some((changed) => changed.id === edit.id)
|
|
236549
237021
|
);
|
|
236550
237022
|
changeRecordPath = ".saasfunnels/feature-installation.json";
|
|
236551
|
-
const
|
|
237023
|
+
const record3 = {
|
|
236552
237024
|
appliedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
236553
237025
|
environment: input.environment,
|
|
236554
237026
|
files: changedEdits.map((edit) => ({
|
|
@@ -236565,7 +237037,7 @@ async function runFeatureSetup(input) {
|
|
|
236565
237037
|
path: change.path
|
|
236566
237038
|
})),
|
|
236567
237039
|
{
|
|
236568
|
-
contents: `${JSON.stringify(
|
|
237040
|
+
contents: `${JSON.stringify(record3, null, 2)}
|
|
236569
237041
|
`,
|
|
236570
237042
|
path: changeRecordPath
|
|
236571
237043
|
}
|
|
@@ -236703,9 +237175,98 @@ Applied reviewed edits. Change record: ${result3.changeRecordPath}` : result3.id
|
|
|
236703
237175
|
].join("\n");
|
|
236704
237176
|
}
|
|
236705
237177
|
|
|
237178
|
+
// src/discovery-coverage.ts
|
|
237179
|
+
var exec3 = promisify3(execFile3);
|
|
237180
|
+
async function discoverCoverageLimitations(cwd2) {
|
|
237181
|
+
const { stdout } = await exec3(
|
|
237182
|
+
"git",
|
|
237183
|
+
["ls-files", "--cached", "--others", "--exclude-standard", "-z", "--", "."],
|
|
237184
|
+
{ cwd: cwd2, maxBuffer: 32 * 1024 * 1024 }
|
|
237185
|
+
);
|
|
237186
|
+
const files = [...new Set(stdout.split("\0").filter(Boolean))].sort();
|
|
237187
|
+
if (files.length > 5e4)
|
|
237188
|
+
throw new Error(
|
|
237189
|
+
"Feature discovery needs attention: more than 50,000 repository files. Narrow the application repository before scanning."
|
|
237190
|
+
);
|
|
237191
|
+
const sources = /* @__PURE__ */ new Map();
|
|
237192
|
+
const results = /* @__PURE__ */ new Map();
|
|
237193
|
+
const record3 = (code, file2) => {
|
|
237194
|
+
const paths = results.get(code) ?? /* @__PURE__ */ new Set();
|
|
237195
|
+
if (paths.size < 12) paths.add(file2);
|
|
237196
|
+
results.set(code, paths);
|
|
237197
|
+
};
|
|
237198
|
+
for (const path of files) {
|
|
237199
|
+
if (path.length > 200 || path.startsWith("/") || path.includes("..") || /[\x00-\x1f]/.test(path) || sensitivePathPattern.test(path) || /secret|credential/i.test(path) || nonProductPath.test(path) || path.split("/").some(
|
|
237200
|
+
(part) => ignoredSegments.has(part) || /^\.next(?:[-.]|$)/.test(part)
|
|
237201
|
+
))
|
|
237202
|
+
continue;
|
|
237203
|
+
const stat = await lstat2(join2(cwd2, path)).catch(() => null);
|
|
237204
|
+
if (!stat?.isFile() || stat.isSymbolicLink()) continue;
|
|
237205
|
+
if (/\.(?:py|rb|go|rs|java|kt|cs|php|ex|exs|scala|swift|vue|svelte)$/.test(
|
|
237206
|
+
path
|
|
237207
|
+
)) {
|
|
237208
|
+
record3("unsupported_language", path);
|
|
237209
|
+
continue;
|
|
237210
|
+
}
|
|
237211
|
+
if (!/\.[cm]?[jt]sx?$/.test(path) || /\.d\.ts$/.test(path) || stat.size > 2e6)
|
|
237212
|
+
continue;
|
|
237213
|
+
const source = await readFile3(join2(cwd2, path), "utf8");
|
|
237214
|
+
sources.set(path, source);
|
|
237215
|
+
const file2 = parseApplicationSource(path, source);
|
|
237216
|
+
const visit = (node) => {
|
|
237217
|
+
if (!isProductNode(node)) return;
|
|
237218
|
+
if ((import_typescript5.default.isVariableDeclaration(node) || import_typescript5.default.isPropertyAssignment(node)) && node.initializer) {
|
|
237219
|
+
const name = node.name.getText(file2).replace(/["'_-]/g, "");
|
|
237220
|
+
let initializer3 = node.initializer;
|
|
237221
|
+
while (import_typescript5.default.isAsExpression(initializer3) || import_typescript5.default.isSatisfiesExpression(initializer3) || import_typescript5.default.isParenthesizedExpression(initializer3))
|
|
237222
|
+
initializer3 = initializer3.expression;
|
|
237223
|
+
const commercialFields = (node2) => {
|
|
237224
|
+
if (import_typescript5.default.isPropertyAssignment(node2) && /^(?:prices?|quotas?|features?|entitlements?|.*Limit|.*Allowance|lookupKey|amount|unit_amount)$/i.test(
|
|
237225
|
+
node2.name.getText(file2).replace(/["']/g, "")
|
|
237226
|
+
))
|
|
237227
|
+
return true;
|
|
237228
|
+
return import_typescript5.default.forEachChild(
|
|
237229
|
+
node2,
|
|
237230
|
+
(child) => commercialFields(child) ? true : void 0
|
|
237231
|
+
) ?? false;
|
|
237232
|
+
};
|
|
237233
|
+
const entitlementObject = /trialfeatures|trialentitlements|externalentitlements/i.test(name) && import_typescript5.default.isObjectLiteralExpression(initializer3) && initializer3.properties.length > 0;
|
|
237234
|
+
if (/(?:addons?|capacitybands?|usagerates?|meteredpricing|trialfeatures|trialentitlements|externalentitlements|seatpricing)/i.test(
|
|
237235
|
+
name
|
|
237236
|
+
) && (import_typescript5.default.isArrayLiteralExpression(initializer3) || import_typescript5.default.isObjectLiteralExpression(initializer3)) && (entitlementObject || commercialFields(initializer3)))
|
|
237237
|
+
record3("commercial_extensions", path);
|
|
237238
|
+
}
|
|
237239
|
+
if (import_typescript5.default.isCallExpression(node)) {
|
|
237240
|
+
const name = import_typescript5.default.isIdentifier(node.expression) ? node.expression.text : import_typescript5.default.isPropertyAccessExpression(node.expression) ? node.expression.name.text : "";
|
|
237241
|
+
if (/^(?:has|check|require|assert|enforce|evaluate|canUse|is)(?:Feature|Entitlement|Quota|UsageLimit)/i.test(
|
|
237242
|
+
name
|
|
237243
|
+
) && !namedFeatureEvidence(path, node.getText(file2)).length)
|
|
237244
|
+
record3("dynamic_access", path);
|
|
237245
|
+
}
|
|
237246
|
+
import_typescript5.default.forEachChild(node, visit);
|
|
237247
|
+
};
|
|
237248
|
+
visit(file2);
|
|
237249
|
+
}
|
|
237250
|
+
const resolvePlanConstant = planConstantResolver(sources);
|
|
237251
|
+
for (const [path, source] of sources) {
|
|
237252
|
+
if (planRestrictionEvidence(path, source).some(
|
|
237253
|
+
(finding) => finding.reference && !resolvePlanConstant(path, finding.reference, finding.line)
|
|
237254
|
+
))
|
|
237255
|
+
record3("dynamic_access", path);
|
|
237256
|
+
}
|
|
237257
|
+
return [...results].map(([code, paths]) => ({ code, files: [...paths] }));
|
|
237258
|
+
}
|
|
237259
|
+
|
|
237260
|
+
// src/setup-run.ts
|
|
237261
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
237262
|
+
import { execFile as execFile4 } from "node:child_process";
|
|
237263
|
+
import { promisify as promisify4 } from "node:util";
|
|
237264
|
+
import { readFile as readFile6, writeFile as writeFile3, mkdir as mkdir3 } from "node:fs/promises";
|
|
237265
|
+
import { join as join5 } from "node:path";
|
|
237266
|
+
|
|
236706
237267
|
// src/plan-sources.ts
|
|
236707
|
-
import { readFile as
|
|
236708
|
-
import { dirname as dirname2, extname as extname2, join as
|
|
237268
|
+
import { readFile as readFile4, readdir as readdir2, lstat as lstat3, writeFile as writeFile2, mkdir as mkdir2 } from "node:fs/promises";
|
|
237269
|
+
import { dirname as dirname2, extname as extname2, join as join3, relative as relative2, resolve as resolve3, sep } from "node:path";
|
|
236709
237270
|
var planSourceApprovalPath = ".saasfunnels/plan-sources.json";
|
|
236710
237271
|
var maxPlanSourceFiles = 12;
|
|
236711
237272
|
var maxPlanSourceCharacters = 512e3;
|
|
@@ -236772,7 +237333,7 @@ async function discoverPlanSourceCandidates(input) {
|
|
|
236772
237333
|
continue;
|
|
236773
237334
|
let entryStat;
|
|
236774
237335
|
try {
|
|
236775
|
-
entryStat = await
|
|
237336
|
+
entryStat = await lstat3(current);
|
|
236776
237337
|
} catch {
|
|
236777
237338
|
continue;
|
|
236778
237339
|
}
|
|
@@ -236782,7 +237343,7 @@ async function discoverPlanSourceCandidates(input) {
|
|
|
236782
237343
|
for (const entry of entries.sort(
|
|
236783
237344
|
(a, b) => a.name.localeCompare(b.name)
|
|
236784
237345
|
)) {
|
|
236785
|
-
queue.push(
|
|
237346
|
+
queue.push(join3(current, entry.name));
|
|
236786
237347
|
}
|
|
236787
237348
|
continue;
|
|
236788
237349
|
}
|
|
@@ -236796,7 +237357,7 @@ async function discoverPlanSourceCandidates(input) {
|
|
|
236796
237357
|
);
|
|
236797
237358
|
continue;
|
|
236798
237359
|
}
|
|
236799
|
-
const contents = await
|
|
237360
|
+
const contents = await readFile4(current, "utf8");
|
|
236800
237361
|
const hasStripePriceId = stripePriceIdPattern.test(contents);
|
|
236801
237362
|
const named = looksLikePlanSource(relativePath);
|
|
236802
237363
|
const looksPriced = billingIntervalPattern.test(contents) && chargeAmountPattern.test(contents);
|
|
@@ -236819,7 +237380,7 @@ async function discoverPlanSourceCandidates(input) {
|
|
|
236819
237380
|
}
|
|
236820
237381
|
async function readApprovedPlanSources(cwd2) {
|
|
236821
237382
|
try {
|
|
236822
|
-
const raw = await
|
|
237383
|
+
const raw = await readFile4(resolve3(cwd2, planSourceApprovalPath), "utf8");
|
|
236823
237384
|
const parsed = JSON.parse(raw);
|
|
236824
237385
|
return Array.isArray(parsed.files) ? parsed.files.filter(
|
|
236825
237386
|
(value) => typeof value === "string"
|
|
@@ -236866,7 +237427,7 @@ async function buildPlanMappingHandoff(input) {
|
|
|
236866
237427
|
if (!kind) {
|
|
236867
237428
|
throw new Error(`${relativePath} is not a supported plan source type.`);
|
|
236868
237429
|
}
|
|
236869
|
-
const content = await
|
|
237430
|
+
const content = await readFile4(resolve3(input.cwd, relativePath), "utf8");
|
|
236870
237431
|
if (content.length > maxPlanSourceCharacters) {
|
|
236871
237432
|
throw new Error(
|
|
236872
237433
|
`${relativePath} is ${content.length} characters; the limit is ${maxPlanSourceCharacters}.`
|
|
@@ -236882,68 +237443,12 @@ function planMappingRequestKey(input) {
|
|
|
236882
237443
|
}
|
|
236883
237444
|
|
|
236884
237445
|
// src/plan-branches.ts
|
|
236885
|
-
import {
|
|
236886
|
-
import {
|
|
237446
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
237447
|
+
import { readdir as readdir3, readFile as readFile5, lstat as lstat4 } from "node:fs/promises";
|
|
237448
|
+
import { extname as extname3, join as join4, relative as relative3, resolve as resolve4, sep as sep2 } from "node:path";
|
|
236887
237449
|
var maxPlanBranchFileCharacters = 2e6;
|
|
236888
237450
|
var codeExtensions = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
236889
237451
|
var nonDefinitionPattern2 = /(^|\/)(__tests__|__mocks__|tests?|specs?|fixtures?|testing|mocks?|mock-data|stories|__stories__)(\/)|\.(test|spec|d|stories)\.[cm]?[jt]sx?$/i;
|
|
236890
|
-
var comparisonPattern = /\b([A-Za-z_$][\w$]*(?:\.[\w$]+)*)\s*(===|==|!==|!=)\s*(?:["'`]([A-Za-z][A-Za-z0-9_ -]{0,39})["'`]|([A-Za-z_$][\w$]*(?:\.[\w$]+){0,2}))/g;
|
|
236891
|
-
var planIdentifierPattern = /(plan|tier|level|subscription|package)/i;
|
|
236892
|
-
var enumOpenPattern = /\b(?:enum|const)\s+([A-Za-z_$][\w$]*)\s*(?:=\s*)?\{/;
|
|
236893
|
-
var memberPattern = /^\s*([A-Za-z_$][\w$]*)\s*[:=]\s*["'`]([A-Za-z][A-Za-z0-9_ -]{0,39})["'`]/;
|
|
236894
|
-
var blockClosePattern = /^\s*\}/;
|
|
236895
|
-
var simpleConstPattern = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*(?::\s*[\w<>[\]|\s]+)?=\s*["'`]([A-Za-z][A-Za-z0-9_ -]{0,39})["'`]/;
|
|
236896
|
-
var denialPattern = /\b(?:throw|redirect|notFound|forbidden)\b|\breturn\s+(?:null|false|undefined)\b|upgrade|paywall|locked|disabled|403/i;
|
|
236897
|
-
var restrictionNamePattern = /\b(?:needs?|requires?|must)[A-Z_]|\b(?:is|has)?(?:Locked|Blocked|Restricted|Gated|Disabled)|upgrade|paywall/i;
|
|
236898
|
-
var numericBranchPattern = /\?\s*[\d_]+\s*:\s*[\d_]+|:\s*[\d_]+\s*[,;)]/;
|
|
236899
|
-
var renderPattern = /<[A-Z][\w.]*|className=|return\s*\(/;
|
|
236900
|
-
var marketingPattern = /\b(?:upgrade|get started|contact sales|choose|current plan|most popular|per month|per year|\/mo\b|\/yr\b)|\$\{?\d/i;
|
|
236901
|
-
var escapePattern = /\breturn\s+(?:null|false|undefined)\b|\bthrow\b|\bredirect\b|\bnotFound\b/;
|
|
236902
|
-
function collectConstants(lines, into) {
|
|
236903
|
-
let container = null;
|
|
236904
|
-
for (const line of lines) {
|
|
236905
|
-
if (container && blockClosePattern.test(line)) {
|
|
236906
|
-
container = null;
|
|
236907
|
-
continue;
|
|
236908
|
-
}
|
|
236909
|
-
if (!container) {
|
|
236910
|
-
const open = line.match(enumOpenPattern);
|
|
236911
|
-
if (open?.[1]) {
|
|
236912
|
-
container = open[1];
|
|
236913
|
-
continue;
|
|
236914
|
-
}
|
|
236915
|
-
const simple = line.match(simpleConstPattern);
|
|
236916
|
-
if (simple?.[1] && simple[2]) record3(into, simple[1], simple[2]);
|
|
236917
|
-
continue;
|
|
236918
|
-
}
|
|
236919
|
-
const member = line.match(memberPattern);
|
|
236920
|
-
if (member?.[1] && member[2]) {
|
|
236921
|
-
record3(into, `${container}.${member[1]}`, member[2]);
|
|
236922
|
-
record3(into, member[1], member[2]);
|
|
236923
|
-
}
|
|
236924
|
-
}
|
|
236925
|
-
}
|
|
236926
|
-
function record3(into, name, value) {
|
|
236927
|
-
const normalized = value.toLowerCase();
|
|
236928
|
-
if (!into.has(name)) {
|
|
236929
|
-
into.set(name, normalized);
|
|
236930
|
-
return;
|
|
236931
|
-
}
|
|
236932
|
-
if (into.get(name) !== normalized) into.set(name, null);
|
|
236933
|
-
}
|
|
236934
|
-
function resolveConstant(index, reference) {
|
|
236935
|
-
const direct = index.get(reference);
|
|
236936
|
-
if (direct !== void 0) return direct;
|
|
236937
|
-
const segments = reference.split(".");
|
|
236938
|
-
if (segments.length > 1) {
|
|
236939
|
-
const tail = segments.slice(-2).join(".");
|
|
236940
|
-
const viaTail = index.get(tail);
|
|
236941
|
-
if (viaTail !== void 0) return viaTail;
|
|
236942
|
-
const viaMember = index.get(segments[segments.length - 1]);
|
|
236943
|
-
if (viaMember !== void 0) return viaMember;
|
|
236944
|
-
}
|
|
236945
|
-
return void 0;
|
|
236946
|
-
}
|
|
236947
237452
|
function normalize2(path) {
|
|
236948
237453
|
return path.split(sep2).join("/");
|
|
236949
237454
|
}
|
|
@@ -236956,51 +237461,11 @@ function allowed2(relativePath, excludes) {
|
|
|
236956
237461
|
if (nonDefinitionPattern2.test(relativePath)) return false;
|
|
236957
237462
|
return !excludes.some((exclude) => relativePath.startsWith(exclude));
|
|
236958
237463
|
}
|
|
236959
|
-
function nearestSymbol2(lines, lineIndex) {
|
|
236960
|
-
for (let index = lineIndex; index >= Math.max(0, lineIndex - 20); index -= 1) {
|
|
236961
|
-
const match = lines[index]?.match(
|
|
236962
|
-
/(?:export\s+)?(?:async\s+)?(?:function|class|const|let|var)\s+([A-Za-z_$][\w$]*)/
|
|
236963
|
-
);
|
|
236964
|
-
if (match?.[1]) return match[1];
|
|
236965
|
-
}
|
|
236966
|
-
return "module";
|
|
236967
|
-
}
|
|
236968
|
-
function assignedName(line) {
|
|
236969
|
-
return line.match(/(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=/)?.[1] ?? null;
|
|
236970
|
-
}
|
|
236971
|
-
function bindingUsages(lines, lineIndex, name) {
|
|
236972
|
-
const reference = new RegExp(`\\b${name}\\b`);
|
|
236973
|
-
const usages = [];
|
|
236974
|
-
lines.forEach((line, index) => {
|
|
236975
|
-
if (index === lineIndex || !reference.test(line)) return;
|
|
236976
|
-
usages.push(line);
|
|
236977
|
-
});
|
|
236978
|
-
return usages.join("\n");
|
|
236979
|
-
}
|
|
236980
|
-
function shapeAt(lines, lineIndex) {
|
|
236981
|
-
const line = lines[lineIndex] ?? "";
|
|
236982
|
-
const window = lines.slice(lineIndex, lineIndex + 4).join("\n");
|
|
236983
|
-
if (numericBranchPattern.test(line)) return "limit";
|
|
236984
|
-
if (renderPattern.test(window) && marketingPattern.test(window) && !escapePattern.test(window)) {
|
|
236985
|
-
return "presentation";
|
|
236986
|
-
}
|
|
236987
|
-
return "boolean";
|
|
236988
|
-
}
|
|
236989
|
-
function polarityAt(lines, lineIndex, negated) {
|
|
236990
|
-
const window = lines.slice(lineIndex, lineIndex + 3).join("\n");
|
|
236991
|
-
const bound = assignedName(lines[lineIndex] ?? "");
|
|
236992
|
-
const named = bound ? restrictionNamePattern.test(bound) : false;
|
|
236993
|
-
const usages = bound ? bindingUsages(lines, lineIndex, bound) : "";
|
|
236994
|
-
if (!named && !denialPattern.test(window) && !denialPattern.test(usages)) {
|
|
236995
|
-
return "unclear";
|
|
236996
|
-
}
|
|
236997
|
-
return negated ? "unclear" : "deny";
|
|
236998
|
-
}
|
|
236999
237464
|
function clusterPlanBranches(branches) {
|
|
237000
237465
|
const clusters = /* @__PURE__ */ new Map();
|
|
237001
237466
|
for (const branch of branches) {
|
|
237002
|
-
const
|
|
237003
|
-
const location =
|
|
237467
|
+
const fullLocation = `${branch.repositoryPath}::${branch.symbol}`;
|
|
237468
|
+
const location = fullLocation.length <= 400 ? fullLocation : `${fullLocation.slice(0, 367)}~${createHash3("sha256").update(fullLocation).digest("hex").slice(0, 32)}`;
|
|
237004
237469
|
const key2 = `${branch.shape}|${location}`;
|
|
237005
237470
|
const existing = clusters.get(key2);
|
|
237006
237471
|
if (existing) existing.push(branch);
|
|
@@ -237031,7 +237496,7 @@ async function discoverPlanBranches(input) {
|
|
|
237031
237496
|
const roots = input.roots ?? [".", ...defaultRoots];
|
|
237032
237497
|
const seen = /* @__PURE__ */ new Set();
|
|
237033
237498
|
const branches = [];
|
|
237034
|
-
const
|
|
237499
|
+
const sources = /* @__PURE__ */ new Map();
|
|
237035
237500
|
const pending = [];
|
|
237036
237501
|
const inRepository = await repositorySourceScope(input.cwd);
|
|
237037
237502
|
const queue = roots.map((root) => resolve4(input.cwd, root));
|
|
@@ -237044,7 +237509,7 @@ async function discoverPlanBranches(input) {
|
|
|
237044
237509
|
continue;
|
|
237045
237510
|
let entryStat;
|
|
237046
237511
|
try {
|
|
237047
|
-
entryStat = await
|
|
237512
|
+
entryStat = await lstat4(current);
|
|
237048
237513
|
} catch {
|
|
237049
237514
|
continue;
|
|
237050
237515
|
}
|
|
@@ -237054,7 +237519,7 @@ async function discoverPlanBranches(input) {
|
|
|
237054
237519
|
for (const entry of entries.sort(
|
|
237055
237520
|
(a, b) => a.name.localeCompare(b.name)
|
|
237056
237521
|
)) {
|
|
237057
|
-
queue.push(
|
|
237522
|
+
queue.push(join4(current, entry.name));
|
|
237058
237523
|
}
|
|
237059
237524
|
continue;
|
|
237060
237525
|
}
|
|
@@ -237064,30 +237529,15 @@ async function discoverPlanBranches(input) {
|
|
|
237064
237529
|
throw new Error(
|
|
237065
237530
|
"Plan discovery found a source file above the 2 MB per-file limit. Split large source files before retrying."
|
|
237066
237531
|
);
|
|
237067
|
-
const
|
|
237068
|
-
|
|
237069
|
-
|
|
237070
|
-
|
|
237071
|
-
|
|
237072
|
-
while (match = comparisonPattern.exec(line)) {
|
|
237073
|
-
const [, identifier, operator, literal2, reference] = match;
|
|
237074
|
-
if (!planIdentifierPattern.test(identifier ?? "")) continue;
|
|
237075
|
-
if (!literal2 && !reference) continue;
|
|
237076
|
-
pending.push({
|
|
237077
|
-
line: lineIndex + 1,
|
|
237078
|
-
literal: literal2 ?? null,
|
|
237079
|
-
negated: operator.startsWith("!"),
|
|
237080
|
-
polarity: polarityAt(lines, lineIndex, operator.startsWith("!")),
|
|
237081
|
-
reference: reference ?? null,
|
|
237082
|
-
repositoryPath: relativePath,
|
|
237083
|
-
shape: shapeAt(lines, lineIndex),
|
|
237084
|
-
symbol: nearestSymbol2(lines, lineIndex)
|
|
237085
|
-
});
|
|
237086
|
-
}
|
|
237087
|
-
});
|
|
237532
|
+
const source = await readFile5(current, "utf8");
|
|
237533
|
+
sources.set(relativePath, source);
|
|
237534
|
+
for (const evidence of planRestrictionEvidence(relativePath, source)) {
|
|
237535
|
+
pending.push({ ...evidence, repositoryPath: relativePath });
|
|
237536
|
+
}
|
|
237088
237537
|
}
|
|
237538
|
+
const resolveConstant = planConstantResolver(sources);
|
|
237089
237539
|
for (const item of pending) {
|
|
237090
|
-
const value = item.literal ? item.literal.toLowerCase() : resolveConstant(
|
|
237540
|
+
const value = item.literal ? item.literal.toLowerCase() : resolveConstant(item.repositoryPath, item.reference, item.line);
|
|
237091
237541
|
if (!value || !planValues.has(value)) continue;
|
|
237092
237542
|
branches.push({
|
|
237093
237543
|
line: item.line,
|
|
@@ -237104,8 +237554,8 @@ async function discoverPlanBranches(input) {
|
|
|
237104
237554
|
}
|
|
237105
237555
|
|
|
237106
237556
|
// src/setup-run.ts
|
|
237107
|
-
var
|
|
237108
|
-
var hash2 = (text) =>
|
|
237557
|
+
var exec4 = promisify4(execFile4);
|
|
237558
|
+
var hash2 = (text) => createHash4("sha256").update(text).digest("hex");
|
|
237109
237559
|
var contextSchema = external_exports.object({
|
|
237110
237560
|
workspaceId: external_exports.string(),
|
|
237111
237561
|
generation: external_exports.string().regex(/^[a-f0-9]{64}$/),
|
|
@@ -237177,15 +237627,15 @@ async function runGuidedSetup(options) {
|
|
|
237177
237627
|
"Connect Stripe and create app credentials in Setup first."
|
|
237178
237628
|
);
|
|
237179
237629
|
try {
|
|
237180
|
-
await
|
|
237181
|
-
await
|
|
237630
|
+
await exec4("git", ["rev-parse", "HEAD"], { cwd: options.cwd });
|
|
237631
|
+
await exec4("git", ["remote", "get-url", "origin"], { cwd: options.cwd });
|
|
237182
237632
|
} catch {
|
|
237183
237633
|
throw new Error(
|
|
237184
237634
|
"Repository setup needed: run this command inside your app\u2019s Git repository with an initial commit and an origin remote. No push or production deploy is required for discovery."
|
|
237185
237635
|
);
|
|
237186
237636
|
}
|
|
237187
|
-
const head = (await
|
|
237188
|
-
const diff = (await
|
|
237637
|
+
const head = (await exec4("git", ["rev-parse", "HEAD"], { cwd: options.cwd })).stdout.trim();
|
|
237638
|
+
const diff = (await exec4(
|
|
237189
237639
|
"git",
|
|
237190
237640
|
[
|
|
237191
237641
|
"diff",
|
|
@@ -237198,7 +237648,7 @@ async function runGuidedSetup(options) {
|
|
|
237198
237648
|
],
|
|
237199
237649
|
{ cwd: options.cwd, maxBuffer: 8e6 }
|
|
237200
237650
|
)).stdout;
|
|
237201
|
-
const untracked = (await
|
|
237651
|
+
const untracked = (await exec4("git", ["ls-files", "--others", "--exclude-standard", "-z"], {
|
|
237202
237652
|
cwd: options.cwd
|
|
237203
237653
|
})).stdout.split("\0").filter(
|
|
237204
237654
|
(path) => path && !path.startsWith(".saasfunnels/") && !/(^|\/)(\.env|node_modules|dist|\.next)(\/|$|\.)/i.test(path)
|
|
@@ -237210,15 +237660,15 @@ async function runGuidedSetup(options) {
|
|
|
237210
237660
|
const sourceHashes = await Promise.all(
|
|
237211
237661
|
untracked.map(async (path) => [
|
|
237212
237662
|
path,
|
|
237213
|
-
hash2(await
|
|
237663
|
+
hash2(await readFile6(join5(options.cwd, path), "utf8"))
|
|
237214
237664
|
])
|
|
237215
237665
|
);
|
|
237216
|
-
const revision = `${head}:${hash2(JSON.stringify([diff, sourceHashes]))}`;
|
|
237217
|
-
const remote = (await
|
|
237666
|
+
const revision = `${head}:${hash2(JSON.stringify(["discovery-quality-v2", diff, sourceHashes]))}`;
|
|
237667
|
+
const remote = (await exec4("git", ["remote", "get-url", "origin"], { cwd: options.cwd })).stdout.trim();
|
|
237218
237668
|
const repositoryKey = safeRepositoryKey(remote);
|
|
237219
|
-
const statePath =
|
|
237669
|
+
const statePath = join5(options.cwd, ".saasfunnels", "setup-run.json");
|
|
237220
237670
|
if (options.resume) {
|
|
237221
|
-
const saved = JSON.parse(await
|
|
237671
|
+
const saved = JSON.parse(await readFile6(statePath, "utf8"));
|
|
237222
237672
|
if (saved.generation !== context.generation || saved.repositoryKey !== repositoryKey || saved.revision !== revision)
|
|
237223
237673
|
throw new Error(
|
|
237224
237674
|
"The app connection or revision changed. Run setup again without --resume."
|
|
@@ -237241,7 +237691,7 @@ async function runGuidedSetup(options) {
|
|
|
237241
237691
|
repositoryRevisionHash: hash2(revision)
|
|
237242
237692
|
})).run;
|
|
237243
237693
|
if (!run) throw new Error("Setup did not return a run.");
|
|
237244
|
-
await mkdir3(
|
|
237694
|
+
await mkdir3(join5(options.cwd, ".saasfunnels"), { recursive: true });
|
|
237245
237695
|
await writeFile3(
|
|
237246
237696
|
statePath,
|
|
237247
237697
|
JSON.stringify(
|
|
@@ -237276,9 +237726,14 @@ async function runGuidedSetup(options) {
|
|
|
237276
237726
|
});
|
|
237277
237727
|
return heartbeat;
|
|
237278
237728
|
};
|
|
237279
|
-
const send = (evidence) => {
|
|
237729
|
+
const send = (evidence, proposals) => {
|
|
237280
237730
|
const currentStage = stage;
|
|
237281
|
-
if (JSON.stringify({
|
|
237731
|
+
if (JSON.stringify({
|
|
237732
|
+
runId: run.id,
|
|
237733
|
+
stage: currentStage,
|
|
237734
|
+
evidence,
|
|
237735
|
+
...proposals ? { proposals } : {}
|
|
237736
|
+
}).length > 1e6)
|
|
237282
237737
|
throw new Error(
|
|
237283
237738
|
"Feature discovery evidence exceeds the upload size limit. Review the source scope before retrying."
|
|
237284
237739
|
);
|
|
@@ -237286,7 +237741,8 @@ async function runGuidedSetup(options) {
|
|
|
237286
237741
|
const result3 = await request("/api/developer-tools/setup/evidence", {
|
|
237287
237742
|
runId: run.id,
|
|
237288
237743
|
stage: currentStage,
|
|
237289
|
-
evidence
|
|
237744
|
+
evidence,
|
|
237745
|
+
...proposals ? { proposals } : {}
|
|
237290
237746
|
});
|
|
237291
237747
|
if (typeof result3.sequence === "number")
|
|
237292
237748
|
run.sequence = result3.sequence;
|
|
@@ -237306,6 +237762,11 @@ async function runGuidedSetup(options) {
|
|
|
237306
237762
|
void update(progressState, progressFailure).catch(() => {
|
|
237307
237763
|
});
|
|
237308
237764
|
}, 3e4);
|
|
237765
|
+
const limitations = await discoverCoverageLimitations(options.cwd);
|
|
237766
|
+
if (limitations.length)
|
|
237767
|
+
options.progress?.(
|
|
237768
|
+
"Some app behavior needs manual review. Coverage details will appear with your findings in Setup."
|
|
237769
|
+
);
|
|
237309
237770
|
options.progress?.(
|
|
237310
237771
|
run.receipts.features ? "2/4 Features already submitted." : "2/4 Discovering features\u2026"
|
|
237311
237772
|
);
|
|
@@ -237317,9 +237778,11 @@ async function runGuidedSetup(options) {
|
|
|
237317
237778
|
environment: context.environment,
|
|
237318
237779
|
apply: false,
|
|
237319
237780
|
manifestOnly: true,
|
|
237781
|
+
freshDiscovery: true,
|
|
237320
237782
|
accept: ["all"]
|
|
237321
237783
|
});
|
|
237322
|
-
|
|
237784
|
+
const unsupportedOnly = scan.coverage.scannedFiles === 0 && !scan.coverage.byteLimitReached && limitations.some((l) => l.code === "unsupported_language");
|
|
237785
|
+
if (!scan.coverage.complete && !unsupportedOnly) {
|
|
237323
237786
|
const reason = scan.coverage.byteLimitReached ? `${scan.coverage.oversizedFileCount} source file(s) exceed the 2 MB per-file limit. Split large source files before retrying.` : !scan.coverage.scannedFiles ? "No JavaScript or TypeScript app files were found in the source roots. Run from the application folder." : "More than 10,000 feature bindings were found. Review the source scope before retrying.";
|
|
237324
237787
|
throw new Error(
|
|
237325
237788
|
`Feature discovery needs attention: ${reason} Scanned ${scan.coverage.scannedFiles} of ${scan.coverage.matchedFiles} files. Nothing was submitted for this stage.`
|
|
@@ -237328,6 +237791,10 @@ async function runGuidedSetup(options) {
|
|
|
237328
237791
|
options.progress?.(
|
|
237329
237792
|
`Scanned ${scan.scannedFileCount} files; found ${scan.manifest.features.length} feature proposals.`
|
|
237330
237793
|
);
|
|
237794
|
+
if (scan.manifest.features.length > 500)
|
|
237795
|
+
throw new Error(
|
|
237796
|
+
"Feature discovery needs attention: more than 500 features. Narrow the application scope before retrying; nothing was submitted."
|
|
237797
|
+
);
|
|
237331
237798
|
if (!scan.ok)
|
|
237332
237799
|
throw new Error(
|
|
237333
237800
|
"Feature discovery needs attention. Run features setup to review the local findings."
|
|
@@ -237338,7 +237805,17 @@ async function runGuidedSetup(options) {
|
|
|
237338
237805
|
repositoryKey,
|
|
237339
237806
|
repositoryRevision: revision,
|
|
237340
237807
|
discoveryRoots: scan.framework.roots
|
|
237341
|
-
})
|
|
237808
|
+
}),
|
|
237809
|
+
scan.manifest.features.map((feature) => ({
|
|
237810
|
+
featureKey: feature.key,
|
|
237811
|
+
name: feature.name,
|
|
237812
|
+
accessModel: feature.accessModel,
|
|
237813
|
+
reason: feature.evidence.some((e) => e.symbol === "plan_catalog") ? "plan_catalog" : feature.accessModel === "limit" ? "usage_check" : feature.evidence.some(
|
|
237814
|
+
(e) => e.bindingKind === "server_enforcement"
|
|
237815
|
+
) ? "access_check" : feature.evidence.some(
|
|
237816
|
+
(e) => e.bindingKind === "browser_presentation"
|
|
237817
|
+
) ? "visibility_gate" : "denied_access"
|
|
237818
|
+
}))
|
|
237342
237819
|
);
|
|
237343
237820
|
}
|
|
237344
237821
|
stage = "plans";
|
|
@@ -237373,8 +237850,8 @@ async function runGuidedSetup(options) {
|
|
|
237373
237850
|
});
|
|
237374
237851
|
let manual = null;
|
|
237375
237852
|
try {
|
|
237376
|
-
manual = await
|
|
237377
|
-
|
|
237853
|
+
manual = await readFile6(
|
|
237854
|
+
join5(options.cwd, ".saasfunnels/setup-pricing.json"),
|
|
237378
237855
|
"utf8"
|
|
237379
237856
|
);
|
|
237380
237857
|
} catch (error51) {
|
|
@@ -237387,7 +237864,7 @@ async function runGuidedSetup(options) {
|
|
|
237387
237864
|
for (const candidate of sources) {
|
|
237388
237865
|
try {
|
|
237389
237866
|
const plans = extractSetupPricing(
|
|
237390
|
-
manual ?? await
|
|
237867
|
+
manual ?? await readFile6(join5(options.cwd, candidate.path), "utf8"),
|
|
237391
237868
|
candidate.kind,
|
|
237392
237869
|
context.catalogPrices
|
|
237393
237870
|
);
|
|
@@ -237416,7 +237893,7 @@ async function runGuidedSetup(options) {
|
|
|
237416
237893
|
});
|
|
237417
237894
|
if (issues.length) {
|
|
237418
237895
|
await writeFile3(
|
|
237419
|
-
|
|
237896
|
+
join5(options.cwd, ".saasfunnels/setup-review.json"),
|
|
237420
237897
|
JSON.stringify({ stage: "plans", issues }, null, 2) + "\n",
|
|
237421
237898
|
{ mode: 384 }
|
|
237422
237899
|
);
|
|
@@ -237431,7 +237908,11 @@ async function runGuidedSetup(options) {
|
|
|
237431
237908
|
options.progress?.(
|
|
237432
237909
|
`Found ${byKey.size} plan proposals in ${reviewedFiles.length} pricing files.`
|
|
237433
237910
|
);
|
|
237434
|
-
await send({
|
|
237911
|
+
await send({
|
|
237912
|
+
plans: [...byKey.values()],
|
|
237913
|
+
reviewedFiles,
|
|
237914
|
+
...limitations.length ? { limitations } : {}
|
|
237915
|
+
});
|
|
237435
237916
|
}
|
|
237436
237917
|
stage = "branches";
|
|
237437
237918
|
const planValues = [
|
|
@@ -237529,11 +238010,11 @@ async function submitApprovedSetupPlans(input) {
|
|
|
237529
238010
|
}
|
|
237530
238011
|
|
|
237531
238012
|
// src/cli.ts
|
|
237532
|
-
import { mkdir as mkdir4, readFile as
|
|
238013
|
+
import { mkdir as mkdir4, readFile as readFile7, writeFile as writeFile4 } from "node:fs/promises";
|
|
237533
238014
|
|
|
237534
238015
|
// src/identity.ts
|
|
237535
238016
|
var SAASFUNNELS_CLI_NAME = "saasfunnels";
|
|
237536
|
-
var SAASFUNNELS_CLI_VERSION = "0.3.
|
|
238017
|
+
var SAASFUNNELS_CLI_VERSION = "0.3.4";
|
|
237537
238018
|
var SAASFUNNELS_PRODUCT_NAME = "SaaSFunnels";
|
|
237538
238019
|
var SAASFUNNELS_DEFAULT_API_BASE_URL = "https://app.saasfunnels.ai";
|
|
237539
238020
|
var SAASFUNNELS_ENV = Object.freeze({
|
|
@@ -238031,7 +238512,7 @@ function featureCatalogMarkdown() {
|
|
|
238031
238512
|
return [
|
|
238032
238513
|
"# SaaSFunnels Feature Catalog Manifest",
|
|
238033
238514
|
"",
|
|
238034
|
-
"The
|
|
238515
|
+
"The local features setup command maintains `.saasfunnels/catalog.yaml`; applying generated changes is Test-only. Guided setup submits structured proposals in the connection's environment after explicit approval, without raw source. Coverage tasks and quota semantics require human review in the current Plans & pricing editor.",
|
|
238035
238516
|
"",
|
|
238036
238517
|
"Required top-level fields:",
|
|
238037
238518
|
"- `schemaVersion: 1`",
|
|
@@ -239359,7 +239840,7 @@ function filesystem(options) {
|
|
|
239359
239840
|
mkdir: async (path, mkdirOptions) => {
|
|
239360
239841
|
await mkdir4(path, mkdirOptions);
|
|
239361
239842
|
},
|
|
239362
|
-
readFile:
|
|
239843
|
+
readFile: readFile7,
|
|
239363
239844
|
writeFile: writeFile4
|
|
239364
239845
|
};
|
|
239365
239846
|
}
|
|
@@ -239397,7 +239878,7 @@ async function readJsonFile(filePath, options) {
|
|
|
239397
239878
|
}
|
|
239398
239879
|
async function commandInit(flags, options) {
|
|
239399
239880
|
const fs = filesystem(options);
|
|
239400
|
-
const configPath =
|
|
239881
|
+
const configPath = join6(cwd(options), ".saasfunnels", "config.json");
|
|
239401
239882
|
const config2 = {
|
|
239402
239883
|
api_base_url: apiBaseUrl2(options, flags),
|
|
239403
239884
|
schema_version: cliSchemaVersion
|
|
@@ -239437,7 +239918,7 @@ async function commandAgentInstall(args, flags, options) {
|
|
|
239437
239918
|
const artifacts = getDeveloperToolAgentHandoffArtifacts({ endpoint });
|
|
239438
239919
|
const artifact = artifacts[target];
|
|
239439
239920
|
const targetPath = flagString(flags, "path") ?? saasFunnelsPublicText(artifact.target_path);
|
|
239440
|
-
const absoluteTarget =
|
|
239921
|
+
const absoluteTarget = join6(cwd(options), targetPath);
|
|
239441
239922
|
const fs = filesystem(options);
|
|
239442
239923
|
await fs.mkdir(dirname3(absoluteTarget), { recursive: true });
|
|
239443
239924
|
await fs.writeFile(
|