aso-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +227 -0
- package/build/cache/sqlite-cache.d.ts +10 -0
- package/build/cache/sqlite-cache.d.ts.map +1 -0
- package/build/cache/sqlite-cache.js +51 -0
- package/build/cache/sqlite-cache.js.map +1 -0
- package/build/data-sources/app-store-connect.d.ts +12 -0
- package/build/data-sources/app-store-connect.d.ts.map +1 -0
- package/build/data-sources/app-store-connect.js +415 -0
- package/build/data-sources/app-store-connect.js.map +1 -0
- package/build/data-sources/app-store.d.ts +7 -0
- package/build/data-sources/app-store.d.ts.map +1 -0
- package/build/data-sources/app-store.js +28 -0
- package/build/data-sources/app-store.js.map +1 -0
- package/build/data-sources/aso-scoring.d.ts +15 -0
- package/build/data-sources/aso-scoring.d.ts.map +1 -0
- package/build/data-sources/aso-scoring.js +140 -0
- package/build/data-sources/aso-scoring.js.map +1 -0
- package/build/data-sources/custom-scoring.d.ts +52 -0
- package/build/data-sources/custom-scoring.d.ts.map +1 -0
- package/build/data-sources/custom-scoring.js +83 -0
- package/build/data-sources/custom-scoring.js.map +1 -0
- package/build/server.d.ts +3 -0
- package/build/server.d.ts.map +1 -0
- package/build/server.js +69 -0
- package/build/server.js.map +1 -0
- package/build/tools/analyze-competitors.d.ts +3 -0
- package/build/tools/analyze-competitors.d.ts.map +1 -0
- package/build/tools/analyze-competitors.js +112 -0
- package/build/tools/analyze-competitors.js.map +1 -0
- package/build/tools/analyze-reviews.d.ts +3 -0
- package/build/tools/analyze-reviews.d.ts.map +1 -0
- package/build/tools/analyze-reviews.js +188 -0
- package/build/tools/analyze-reviews.js.map +1 -0
- package/build/tools/clear-cache.d.ts +3 -0
- package/build/tools/clear-cache.d.ts.map +1 -0
- package/build/tools/clear-cache.js +32 -0
- package/build/tools/clear-cache.js.map +1 -0
- package/build/tools/connect-get-app.d.ts +3 -0
- package/build/tools/connect-get-app.d.ts.map +1 -0
- package/build/tools/connect-get-app.js +56 -0
- package/build/tools/connect-get-app.js.map +1 -0
- package/build/tools/connect-get-metadata.d.ts +3 -0
- package/build/tools/connect-get-metadata.d.ts.map +1 -0
- package/build/tools/connect-get-metadata.js +73 -0
- package/build/tools/connect-get-metadata.js.map +1 -0
- package/build/tools/connect-list-localizations.d.ts +3 -0
- package/build/tools/connect-list-localizations.d.ts.map +1 -0
- package/build/tools/connect-list-localizations.js +55 -0
- package/build/tools/connect-list-localizations.js.map +1 -0
- package/build/tools/connect-setup.d.ts +3 -0
- package/build/tools/connect-setup.d.ts.map +1 -0
- package/build/tools/connect-setup.js +47 -0
- package/build/tools/connect-setup.js.map +1 -0
- package/build/tools/connect-update-metadata.d.ts +3 -0
- package/build/tools/connect-update-metadata.d.ts.map +1 -0
- package/build/tools/connect-update-metadata.js +176 -0
- package/build/tools/connect-update-metadata.js.map +1 -0
- package/build/tools/discover-keywords.d.ts +3 -0
- package/build/tools/discover-keywords.d.ts.map +1 -0
- package/build/tools/discover-keywords.js +195 -0
- package/build/tools/discover-keywords.js.map +1 -0
- package/build/tools/generate-aso-brief.d.ts +3 -0
- package/build/tools/generate-aso-brief.d.ts.map +1 -0
- package/build/tools/generate-aso-brief.js +295 -0
- package/build/tools/generate-aso-brief.js.map +1 -0
- package/build/tools/get-app-details.d.ts +3 -0
- package/build/tools/get-app-details.d.ts.map +1 -0
- package/build/tools/get-app-details.js +89 -0
- package/build/tools/get-app-details.js.map +1 -0
- package/build/tools/get-aso-report.d.ts +3 -0
- package/build/tools/get-aso-report.d.ts.map +1 -0
- package/build/tools/get-aso-report.js +168 -0
- package/build/tools/get-aso-report.js.map +1 -0
- package/build/tools/keyword-gap.d.ts +3 -0
- package/build/tools/keyword-gap.d.ts.map +1 -0
- package/build/tools/keyword-gap.js +116 -0
- package/build/tools/keyword-gap.js.map +1 -0
- package/build/tools/localized-keywords.d.ts +3 -0
- package/build/tools/localized-keywords.d.ts.map +1 -0
- package/build/tools/localized-keywords.js +107 -0
- package/build/tools/localized-keywords.js.map +1 -0
- package/build/tools/optimize-metadata.d.ts +3 -0
- package/build/tools/optimize-metadata.d.ts.map +1 -0
- package/build/tools/optimize-metadata.js +156 -0
- package/build/tools/optimize-metadata.js.map +1 -0
- package/build/tools/search-keywords.d.ts +3 -0
- package/build/tools/search-keywords.d.ts.map +1 -0
- package/build/tools/search-keywords.js +65 -0
- package/build/tools/search-keywords.js.map +1 -0
- package/build/tools/suggest-keywords.d.ts +3 -0
- package/build/tools/suggest-keywords.d.ts.map +1 -0
- package/build/tools/suggest-keywords.js +71 -0
- package/build/tools/suggest-keywords.js.map +1 -0
- package/build/tools/track-ranking.d.ts +3 -0
- package/build/tools/track-ranking.d.ts.map +1 -0
- package/build/tools/track-ranking.js +94 -0
- package/build/tools/track-ranking.js.map +1 -0
- package/build/types/index.d.ts +151 -0
- package/build/types/index.d.ts.map +1 -0
- package/build/types/index.js +2 -0
- package/build/types/index.js.map +1 -0
- package/build/utils/constants.d.ts +40 -0
- package/build/utils/constants.d.ts.map +1 -0
- package/build/utils/constants.js +35 -0
- package/build/utils/constants.js.map +1 -0
- package/build/utils/formatters.d.ts +9 -0
- package/build/utils/formatters.d.ts.map +1 -0
- package/build/utils/formatters.js +37 -0
- package/build/utils/formatters.js.map +1 -0
- package/build/utils/localization.d.ts +7 -0
- package/build/utils/localization.d.ts.map +1 -0
- package/build/utils/localization.js +63 -0
- package/build/utils/localization.js.map +1 -0
- package/build/utils/rate-limiter.d.ts +7 -0
- package/build/utils/rate-limiter.d.ts.map +1 -0
- package/build/utils/rate-limiter.js +23 -0
- package/build/utils/rate-limiter.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom ASO Scoring Algorithm
|
|
3
|
+
* Provides self-calculated metrics independent of Apple Search Ads popularity issues.
|
|
4
|
+
*/
|
|
5
|
+
export interface CustomScore {
|
|
6
|
+
visibilityScore: number;
|
|
7
|
+
competitiveScore: number;
|
|
8
|
+
opportunityScore: number;
|
|
9
|
+
overallScore: number;
|
|
10
|
+
}
|
|
11
|
+
export interface KeywordOpportunity {
|
|
12
|
+
keyword: string;
|
|
13
|
+
score: number;
|
|
14
|
+
reason: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Calculates visibility score from an app's ASO metrics.
|
|
18
|
+
* Weights factors like rating, review count, and ranking.
|
|
19
|
+
*/
|
|
20
|
+
export declare function calculateVisibilityScore(params: {
|
|
21
|
+
rating: number;
|
|
22
|
+
reviewCount: number;
|
|
23
|
+
rankInKeyword?: number;
|
|
24
|
+
totalAppsInKeyword?: number;
|
|
25
|
+
}): number;
|
|
26
|
+
/**
|
|
27
|
+
* Calculates the competitive score for a keyword.
|
|
28
|
+
* Determines difficulty by analyzing the strength of top-ranking apps.
|
|
29
|
+
*/
|
|
30
|
+
export declare function calculateCompetitiveScore(topApps: {
|
|
31
|
+
rating: number;
|
|
32
|
+
reviews: number;
|
|
33
|
+
free: boolean;
|
|
34
|
+
}[]): number;
|
|
35
|
+
/**
|
|
36
|
+
* Keyword opportunity score: High traffic + low difficulty = high opportunity
|
|
37
|
+
*/
|
|
38
|
+
export declare function calculateOpportunityScore(traffic: number, difficulty: number): number;
|
|
39
|
+
/**
|
|
40
|
+
* Combines all scores to produce an overall ASO score.
|
|
41
|
+
*/
|
|
42
|
+
export declare function calculateOverallScore(params: {
|
|
43
|
+
visibilityScore: number;
|
|
44
|
+
competitiveScore: number;
|
|
45
|
+
opportunityScore: number;
|
|
46
|
+
}): number;
|
|
47
|
+
/**
|
|
48
|
+
* Extracts keywords from an app's title.
|
|
49
|
+
* Filters out stop words.
|
|
50
|
+
*/
|
|
51
|
+
export declare function extractTitleKeywords(title: string): string[];
|
|
52
|
+
//# sourceMappingURL=custom-scoring.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom-scoring.d.ts","sourceRoot":"","sources":["../../src/data-sources/custom-scoring.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,WAAW;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B,GAAG,MAAM,CAiBT;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;CACf,EAAE,GAAG,MAAM,CAoBX;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,MAAM,CAKR;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE;IAC5C,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,GAAG,MAAM,CAST;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAiB5D"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom ASO Scoring Algorithm
|
|
3
|
+
* Provides self-calculated metrics independent of Apple Search Ads popularity issues.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Calculates visibility score from an app's ASO metrics.
|
|
7
|
+
* Weights factors like rating, review count, and ranking.
|
|
8
|
+
*/
|
|
9
|
+
export function calculateVisibilityScore(params) {
|
|
10
|
+
const { rating, reviewCount, rankInKeyword, totalAppsInKeyword } = params;
|
|
11
|
+
// Rating contribution (0-3 points): 4.5+ = 3, 4.0+ = 2, 3.0+ = 1
|
|
12
|
+
const ratingScore = rating >= 4.5 ? 3 : rating >= 4.0 ? 2 : rating >= 3.0 ? 1 : 0;
|
|
13
|
+
// Review count contribution (0-3 points): logarithmic scale
|
|
14
|
+
const reviewScore = Math.min(3, Math.log10(Math.max(1, reviewCount)) / 1.5);
|
|
15
|
+
// Ranking contribution (0-4 points)
|
|
16
|
+
let rankScore = 2; // default medium
|
|
17
|
+
if (rankInKeyword !== undefined && totalAppsInKeyword) {
|
|
18
|
+
const percentile = 1 - rankInKeyword / totalAppsInKeyword;
|
|
19
|
+
rankScore = percentile * 4;
|
|
20
|
+
}
|
|
21
|
+
return Math.min(10, ratingScore + reviewScore + rankScore);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Calculates the competitive score for a keyword.
|
|
25
|
+
* Determines difficulty by analyzing the strength of top-ranking apps.
|
|
26
|
+
*/
|
|
27
|
+
export function calculateCompetitiveScore(topApps) {
|
|
28
|
+
if (topApps.length === 0)
|
|
29
|
+
return 0;
|
|
30
|
+
const avgRating = topApps.reduce((sum, a) => sum + (a.rating || 0), 0) / topApps.length;
|
|
31
|
+
const avgReviews = topApps.reduce((sum, a) => sum + (a.reviews || 0), 0) / topApps.length;
|
|
32
|
+
const freeRatio = topApps.filter((a) => a.free).length / topApps.length;
|
|
33
|
+
// High rating = harder (0-3)
|
|
34
|
+
const ratingDifficulty = (avgRating / 5) * 3;
|
|
35
|
+
// Many reviews = harder (0-4, logarithmic)
|
|
36
|
+
const reviewDifficulty = Math.min(4, Math.log10(Math.max(1, avgReviews)) / 1.25);
|
|
37
|
+
// Mostly free = harder (0-3)
|
|
38
|
+
const freeDifficulty = freeRatio * 3;
|
|
39
|
+
return Math.min(10, ratingDifficulty + reviewDifficulty + freeDifficulty);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Keyword opportunity score: High traffic + low difficulty = high opportunity
|
|
43
|
+
*/
|
|
44
|
+
export function calculateOpportunityScore(traffic, difficulty) {
|
|
45
|
+
if (traffic === 0 && difficulty === 0)
|
|
46
|
+
return 5;
|
|
47
|
+
// high traffic + low difficulty = high score
|
|
48
|
+
const raw = (traffic * 1.5 - difficulty * 0.8 + 5);
|
|
49
|
+
return Math.max(0, Math.min(10, raw));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Combines all scores to produce an overall ASO score.
|
|
53
|
+
*/
|
|
54
|
+
export function calculateOverallScore(params) {
|
|
55
|
+
const { visibilityScore, competitiveScore, opportunityScore } = params;
|
|
56
|
+
// Weights: visibility 40%, opportunity 35%, competitive (inverse) 25%
|
|
57
|
+
const competitiveInverse = 10 - competitiveScore;
|
|
58
|
+
return (visibilityScore * 0.4 +
|
|
59
|
+
opportunityScore * 0.35 +
|
|
60
|
+
competitiveInverse * 0.25);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Extracts keywords from an app's title.
|
|
64
|
+
* Filters out stop words.
|
|
65
|
+
*/
|
|
66
|
+
export function extractTitleKeywords(title) {
|
|
67
|
+
const stopWords = new Set([
|
|
68
|
+
"the", "a", "an", "and", "or", "but", "in", "on", "at", "to", "for",
|
|
69
|
+
"of", "with", "by", "from", "is", "it", "this", "that", "are", "was",
|
|
70
|
+
"be", "has", "had", "not", "no", "do", "does", "did",
|
|
71
|
+
// Turkish stop words
|
|
72
|
+
"ve", "ile", "bir", "bu", "da", "de", "mi", "mu", "için", "gibi",
|
|
73
|
+
"olan", "olarak", "den", "dan", "ya", "en",
|
|
74
|
+
// App Store common
|
|
75
|
+
"-", "&", "|", ":", "/",
|
|
76
|
+
]);
|
|
77
|
+
return title
|
|
78
|
+
.toLowerCase()
|
|
79
|
+
.split(/[\s\-&|:\/,\.]+/)
|
|
80
|
+
.map((w) => w.trim())
|
|
81
|
+
.filter((w) => w.length > 1 && !stopWords.has(w));
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=custom-scoring.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"custom-scoring.js","sourceRoot":"","sources":["../../src/data-sources/custom-scoring.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":""}
|
package/build/server.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import dotenv from "dotenv";
|
|
5
|
+
// Phase 1 tools
|
|
6
|
+
import { registerSearchKeywords } from "./tools/search-keywords.js";
|
|
7
|
+
import { registerSuggestKeywords } from "./tools/suggest-keywords.js";
|
|
8
|
+
import { registerGetAppDetails } from "./tools/get-app-details.js";
|
|
9
|
+
// Phase 2 tools
|
|
10
|
+
import { registerAnalyzeCompetitors } from "./tools/analyze-competitors.js";
|
|
11
|
+
import { registerOptimizeMetadata } from "./tools/optimize-metadata.js";
|
|
12
|
+
import { registerAnalyzeReviews } from "./tools/analyze-reviews.js";
|
|
13
|
+
import { registerTrackRanking } from "./tools/track-ranking.js";
|
|
14
|
+
import { registerKeywordGap } from "./tools/keyword-gap.js";
|
|
15
|
+
// Phase 3 tools
|
|
16
|
+
import { registerLocalizedKeywords } from "./tools/localized-keywords.js";
|
|
17
|
+
import { registerGetAsoReport } from "./tools/get-aso-report.js";
|
|
18
|
+
// ASO Generation tools
|
|
19
|
+
import { registerDiscoverKeywords } from "./tools/discover-keywords.js";
|
|
20
|
+
import { registerGenerateAsoBrief } from "./tools/generate-aso-brief.js";
|
|
21
|
+
// Phase 5: App Store Connect tools
|
|
22
|
+
import { registerConnectSetup } from "./tools/connect-setup.js";
|
|
23
|
+
import { registerConnectGetApp } from "./tools/connect-get-app.js";
|
|
24
|
+
import { registerConnectGetMetadata } from "./tools/connect-get-metadata.js";
|
|
25
|
+
import { registerConnectUpdateMetadata } from "./tools/connect-update-metadata.js";
|
|
26
|
+
import { registerConnectListLocalizations } from "./tools/connect-list-localizations.js";
|
|
27
|
+
// Utility tools
|
|
28
|
+
import { registerClearCache } from "./tools/clear-cache.js";
|
|
29
|
+
import { initCache } from "./cache/sqlite-cache.js";
|
|
30
|
+
dotenv.config();
|
|
31
|
+
const server = new McpServer({
|
|
32
|
+
name: "aso-mcp",
|
|
33
|
+
version: "1.0.0",
|
|
34
|
+
});
|
|
35
|
+
// Initialize cache
|
|
36
|
+
initCache();
|
|
37
|
+
// Register Phase 1 tools
|
|
38
|
+
registerSearchKeywords(server);
|
|
39
|
+
registerSuggestKeywords(server);
|
|
40
|
+
registerGetAppDetails(server);
|
|
41
|
+
// Register Phase 2 tools
|
|
42
|
+
registerAnalyzeCompetitors(server);
|
|
43
|
+
registerOptimizeMetadata(server);
|
|
44
|
+
registerAnalyzeReviews(server);
|
|
45
|
+
registerTrackRanking(server);
|
|
46
|
+
registerKeywordGap(server);
|
|
47
|
+
// Register Phase 3 tools
|
|
48
|
+
registerLocalizedKeywords(server);
|
|
49
|
+
registerGetAsoReport(server);
|
|
50
|
+
// Register ASO Generation tools
|
|
51
|
+
registerDiscoverKeywords(server);
|
|
52
|
+
registerGenerateAsoBrief(server);
|
|
53
|
+
// Register Phase 5: App Store Connect tools
|
|
54
|
+
registerConnectSetup(server);
|
|
55
|
+
registerConnectGetApp(server);
|
|
56
|
+
registerConnectGetMetadata(server);
|
|
57
|
+
registerConnectUpdateMetadata(server);
|
|
58
|
+
registerConnectListLocalizations(server);
|
|
59
|
+
// Register Utility tools
|
|
60
|
+
registerClearCache(server);
|
|
61
|
+
// Start server
|
|
62
|
+
const transport = new StdioServerTransport();
|
|
63
|
+
await server.connect(transport);
|
|
64
|
+
// Graceful shutdown
|
|
65
|
+
process.on("SIGINT", async () => {
|
|
66
|
+
await server.close();
|
|
67
|
+
process.exit(0);
|
|
68
|
+
});
|
|
69
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,gBAAgB;AAChB,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,gBAAgB;AAChB,OAAO,EAAE,0BAA0B,EAAE,MAAM,gCAAgC,CAAC;AAC5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,gBAAgB;AAChB,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAC1E,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEjE,uBAAuB;AACvB,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC;AAEzE,mCAAmC;AACnC,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AACnF,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AAEzF,gBAAgB;AAChB,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD,MAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,mBAAmB;AACnB,SAAS,EAAE,CAAC;AAEZ,yBAAyB;AACzB,sBAAsB,CAAC,MAAM,CAAC,CAAC;AAC/B,uBAAuB,CAAC,MAAM,CAAC,CAAC;AAChC,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAE9B,yBAAyB;AACzB,0BAA0B,CAAC,MAAM,CAAC,CAAC;AACnC,wBAAwB,CAAC,MAAM,CAAC,CAAC;AACjC,sBAAsB,CAAC,MAAM,CAAC,CAAC;AAC/B,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAC7B,kBAAkB,CAAC,MAAM,CAAC,CAAC;AAE3B,yBAAyB;AACzB,yBAAyB,CAAC,MAAM,CAAC,CAAC;AAClC,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAE7B,gCAAgC;AAChC,wBAAwB,CAAC,MAAM,CAAC,CAAC;AACjC,wBAAwB,CAAC,MAAM,CAAC,CAAC;AAEjC,4CAA4C;AAC5C,oBAAoB,CAAC,MAAM,CAAC,CAAC;AAC7B,qBAAqB,CAAC,MAAM,CAAC,CAAC;AAC9B,0BAA0B,CAAC,MAAM,CAAC,CAAC;AACnC,6BAA6B,CAAC,MAAM,CAAC,CAAC;AACtC,gCAAgC,CAAC,MAAM,CAAC,CAAC;AAEzC,yBAAyB;AACzB,kBAAkB,CAAC,MAAM,CAAC,CAAC;AAE3B,eAAe;AACf,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAEhC,oBAAoB;AACpB,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;IAC9B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-competitors.d.ts","sourceRoot":"","sources":["../../src/tools/analyze-competitors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAWpE,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,SAAS,QA6H3D"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { searchApps } from "../data-sources/app-store.js";
|
|
3
|
+
import { getScores } from "../data-sources/aso-scoring.js";
|
|
4
|
+
import { getFromCache, setCache } from "../cache/sqlite-cache.js";
|
|
5
|
+
import { CACHE_TTL } from "../utils/constants.js";
|
|
6
|
+
import { calculateCompetitiveScore, extractTitleKeywords, } from "../data-sources/custom-scoring.js";
|
|
7
|
+
export function registerAnalyzeCompetitors(server) {
|
|
8
|
+
server.tool("analyze_competitors", "Fetches and compares metadata of top-ranking apps for a keyword, and performs keyword gap analysis. Used to understand the competitive landscape.", {
|
|
9
|
+
keyword: z.string().describe("Keyword to analyze"),
|
|
10
|
+
country: z
|
|
11
|
+
.string()
|
|
12
|
+
.default("tr")
|
|
13
|
+
.describe("Country code (tr, us, de, gb, fr...)"),
|
|
14
|
+
num: z
|
|
15
|
+
.number()
|
|
16
|
+
.default(10)
|
|
17
|
+
.describe("Number of competitor apps to analyze"),
|
|
18
|
+
}, async ({ keyword, country, num }) => {
|
|
19
|
+
const cacheKey = `competitors:${keyword}:${country}:${num}`;
|
|
20
|
+
const cached = getFromCache(cacheKey);
|
|
21
|
+
if (cached) {
|
|
22
|
+
return { content: [{ type: "text", text: cached }] };
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const topApps = await searchApps(keyword, country, num);
|
|
26
|
+
// Extract title keywords for each app
|
|
27
|
+
const appsWithKeywords = topApps.map((app) => {
|
|
28
|
+
const titleKeywords = extractTitleKeywords(app.title || "");
|
|
29
|
+
return {
|
|
30
|
+
title: app.title,
|
|
31
|
+
developer: app.developer,
|
|
32
|
+
rating: app.score || 0,
|
|
33
|
+
reviews: app.reviews || 0,
|
|
34
|
+
free: app.free,
|
|
35
|
+
price: app.price || 0,
|
|
36
|
+
url: app.url,
|
|
37
|
+
titleKeywords,
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
// Keyword frequency analysis
|
|
41
|
+
const keywordFrequency = {};
|
|
42
|
+
for (const app of appsWithKeywords) {
|
|
43
|
+
for (const kw of app.titleKeywords) {
|
|
44
|
+
keywordFrequency[kw] = (keywordFrequency[kw] || 0) + 1;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Common keywords (appearing in 2+ apps)
|
|
48
|
+
const commonKeywords = Object.entries(keywordFrequency)
|
|
49
|
+
.filter(([, count]) => count >= 2)
|
|
50
|
+
.sort((a, b) => b[1] - a[1])
|
|
51
|
+
.map(([kw]) => kw);
|
|
52
|
+
// All unique keywords
|
|
53
|
+
const allKeywords = [...new Set(appsWithKeywords.flatMap((a) => a.titleKeywords))];
|
|
54
|
+
// Keyword gap: keywords not in commonKeywords (opportunity)
|
|
55
|
+
const commonSet = new Set(commonKeywords);
|
|
56
|
+
const keywordGap = allKeywords.filter((kw) => !commonSet.has(kw));
|
|
57
|
+
// Metrics
|
|
58
|
+
const avgRating = appsWithKeywords.reduce((s, a) => s + a.rating, 0) /
|
|
59
|
+
appsWithKeywords.length;
|
|
60
|
+
const avgReviews = appsWithKeywords.reduce((s, a) => s + a.reviews, 0) /
|
|
61
|
+
appsWithKeywords.length;
|
|
62
|
+
const freePercentage = (appsWithKeywords.filter((a) => a.free).length /
|
|
63
|
+
appsWithKeywords.length) *
|
|
64
|
+
100;
|
|
65
|
+
// Top developers
|
|
66
|
+
const devFrequency = {};
|
|
67
|
+
for (const app of appsWithKeywords) {
|
|
68
|
+
devFrequency[app.developer] = (devFrequency[app.developer] || 0) + 1;
|
|
69
|
+
}
|
|
70
|
+
const topDevelopers = Object.entries(devFrequency)
|
|
71
|
+
.sort((a, b) => b[1] - a[1])
|
|
72
|
+
.slice(0, 5)
|
|
73
|
+
.map(([dev]) => dev);
|
|
74
|
+
// Competitive score
|
|
75
|
+
const competitiveScore = calculateCompetitiveScore(appsWithKeywords);
|
|
76
|
+
// Main keyword score
|
|
77
|
+
let keywordScores = { traffic: 0, difficulty: 0 };
|
|
78
|
+
try {
|
|
79
|
+
keywordScores = await getScores(keyword, country);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// Continue if scoring fails
|
|
83
|
+
}
|
|
84
|
+
const result = {
|
|
85
|
+
keyword,
|
|
86
|
+
country,
|
|
87
|
+
competitiveScore: Math.round(competitiveScore * 10) / 10,
|
|
88
|
+
keywordScores,
|
|
89
|
+
apps: appsWithKeywords,
|
|
90
|
+
commonKeywords,
|
|
91
|
+
keywordGap,
|
|
92
|
+
metrics: {
|
|
93
|
+
avgRating: Math.round(avgRating * 100) / 100,
|
|
94
|
+
avgReviews: Math.round(avgReviews),
|
|
95
|
+
freePercentage: Math.round(freePercentage),
|
|
96
|
+
topDevelopers,
|
|
97
|
+
totalAppsAnalyzed: appsWithKeywords.length,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
const resultText = JSON.stringify(result, null, 2);
|
|
101
|
+
setCache(cacheKey, resultText, CACHE_TTL.SEARCH_RESULTS);
|
|
102
|
+
return { content: [{ type: "text", text: resultText }] };
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
return {
|
|
106
|
+
content: [{ type: "text", text: `Error: ${error.message}` }],
|
|
107
|
+
isError: true,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=analyze-competitors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-competitors.js","sourceRoot":"","sources":["../../src/tools/analyze-competitors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-reviews.d.ts","sourceRoot":"","sources":["../../src/tools/analyze-reviews.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAwEpE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,QA4IvD"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getAppDetails, getReviews } from "../data-sources/app-store.js";
|
|
3
|
+
import { getFromCache, setCache } from "../cache/sqlite-cache.js";
|
|
4
|
+
import { CACHE_TTL } from "../utils/constants.js";
|
|
5
|
+
// Simple sentiment keywords
|
|
6
|
+
const POSITIVE_WORDS = new Set([
|
|
7
|
+
// Turkish
|
|
8
|
+
"harika", "mukemmel", "super", "guzel", "kolay", "hizli", "sevdim",
|
|
9
|
+
"basarili", "kaliteli", "tavsiye", "ederim", "ideal", "faydali",
|
|
10
|
+
"kullanisli", "pratik", "efektif", "begendim",
|
|
11
|
+
// English
|
|
12
|
+
"great", "amazing", "awesome", "love", "excellent", "perfect",
|
|
13
|
+
"good", "best", "fantastic", "wonderful", "helpful", "easy",
|
|
14
|
+
"fast", "recommend", "nice", "useful",
|
|
15
|
+
]);
|
|
16
|
+
const NEGATIVE_WORDS = new Set([
|
|
17
|
+
// Turkish
|
|
18
|
+
"kotu", "berbat", "yavaş", "hata", "bug", "cokma", "calısmiyor",
|
|
19
|
+
"bozuk", "sikiyor", "reklam", "pahali", "gereksiz", "zor",
|
|
20
|
+
"karmasik", "siliyorum", "cöp", "rezalet", "felaket", "saçma",
|
|
21
|
+
// English
|
|
22
|
+
"bad", "terrible", "awful", "hate", "worst", "horrible", "slow",
|
|
23
|
+
"crash", "bug", "broken", "ads", "expensive", "useless",
|
|
24
|
+
"annoying", "frustrating", "delete", "uninstall",
|
|
25
|
+
]);
|
|
26
|
+
const FEATURE_INDICATORS = [
|
|
27
|
+
// Turkish
|
|
28
|
+
"eklensin", "eklenmeli", "olsa", "istiyorum", "lazim", "gerek",
|
|
29
|
+
"olmali", "bekliyorum", "güncelleme", "özellik",
|
|
30
|
+
// English
|
|
31
|
+
"should", "please add", "would be nice", "wish", "need", "want",
|
|
32
|
+
"feature request", "missing",
|
|
33
|
+
];
|
|
34
|
+
function analyzeSentiment(text) {
|
|
35
|
+
const lower = text.toLowerCase();
|
|
36
|
+
const words = lower.split(/\s+/);
|
|
37
|
+
let positiveCount = 0;
|
|
38
|
+
let negativeCount = 0;
|
|
39
|
+
for (const word of words) {
|
|
40
|
+
if (POSITIVE_WORDS.has(word))
|
|
41
|
+
positiveCount++;
|
|
42
|
+
if (NEGATIVE_WORDS.has(word))
|
|
43
|
+
negativeCount++;
|
|
44
|
+
}
|
|
45
|
+
if (positiveCount > negativeCount)
|
|
46
|
+
return "positive";
|
|
47
|
+
if (negativeCount > positiveCount)
|
|
48
|
+
return "negative";
|
|
49
|
+
return "neutral";
|
|
50
|
+
}
|
|
51
|
+
function isFeatureRequest(text) {
|
|
52
|
+
const lower = text.toLowerCase();
|
|
53
|
+
return FEATURE_INDICATORS.some((indicator) => lower.includes(indicator));
|
|
54
|
+
}
|
|
55
|
+
function extractKeywords(text) {
|
|
56
|
+
const stopWords = new Set([
|
|
57
|
+
"the", "a", "an", "and", "or", "but", "in", "on", "at", "to", "for",
|
|
58
|
+
"of", "is", "it", "this", "that", "ve", "ile", "bir", "bu", "da",
|
|
59
|
+
"de", "mi", "mu", "icin", "çok", "var", "ben", "app", "uygulama",
|
|
60
|
+
]);
|
|
61
|
+
return text
|
|
62
|
+
.toLowerCase()
|
|
63
|
+
.split(/[\s,.!?;:]+/)
|
|
64
|
+
.filter((w) => w.length > 2 && !stopWords.has(w));
|
|
65
|
+
}
|
|
66
|
+
export function registerAnalyzeReviews(server) {
|
|
67
|
+
server.tool("analyze_reviews", "Performs sentiment analysis on an app's user reviews, extracts complaints and feature requests. Provides keyword insights for ASO.", {
|
|
68
|
+
appId: z
|
|
69
|
+
.string()
|
|
70
|
+
.describe("App Store app ID or bundle ID"),
|
|
71
|
+
country: z
|
|
72
|
+
.string()
|
|
73
|
+
.default("tr")
|
|
74
|
+
.describe("Country code"),
|
|
75
|
+
pages: z
|
|
76
|
+
.number()
|
|
77
|
+
.default(3)
|
|
78
|
+
.describe("Number of review pages to fetch (each page ~50 reviews)"),
|
|
79
|
+
}, async ({ appId, country, pages }) => {
|
|
80
|
+
const cacheKey = `reviews:${appId}:${country}:${pages}`;
|
|
81
|
+
const cached = getFromCache(cacheKey);
|
|
82
|
+
if (cached) {
|
|
83
|
+
return { content: [{ type: "text", text: cached }] };
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
// Get app info (numeric ID required)
|
|
87
|
+
const app = await getAppDetails(appId, country);
|
|
88
|
+
const numericId = app.id;
|
|
89
|
+
// Fetch reviews
|
|
90
|
+
const allReviews = [];
|
|
91
|
+
for (let page = 1; page <= pages; page++) {
|
|
92
|
+
try {
|
|
93
|
+
const pageReviews = await getReviews(numericId, country, page);
|
|
94
|
+
allReviews.push(...pageReviews);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
break; // no more pages
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (allReviews.length === 0) {
|
|
101
|
+
return {
|
|
102
|
+
content: [
|
|
103
|
+
{
|
|
104
|
+
type: "text",
|
|
105
|
+
text: JSON.stringify({
|
|
106
|
+
appId,
|
|
107
|
+
message: "No reviews found for this app.",
|
|
108
|
+
}),
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
// Sentiment analysis
|
|
114
|
+
let positive = 0;
|
|
115
|
+
let negative = 0;
|
|
116
|
+
let neutral = 0;
|
|
117
|
+
const complaints = [];
|
|
118
|
+
const featureRequests = [];
|
|
119
|
+
const keywordMap = {};
|
|
120
|
+
for (const review of allReviews) {
|
|
121
|
+
const text = review.text || review.body || "";
|
|
122
|
+
const title = review.title || "";
|
|
123
|
+
const fullText = `${title} ${text}`;
|
|
124
|
+
const sentiment = analyzeSentiment(fullText);
|
|
125
|
+
if (sentiment === "positive")
|
|
126
|
+
positive++;
|
|
127
|
+
else if (sentiment === "negative")
|
|
128
|
+
negative++;
|
|
129
|
+
else
|
|
130
|
+
neutral++;
|
|
131
|
+
// Complaints (negative reviews)
|
|
132
|
+
if (sentiment === "negative" && text.length > 10) {
|
|
133
|
+
complaints.push(text.length > 150 ? text.slice(0, 150) + "..." : text);
|
|
134
|
+
}
|
|
135
|
+
// Feature requests
|
|
136
|
+
if (isFeatureRequest(fullText)) {
|
|
137
|
+
featureRequests.push(fullText.length > 150 ? fullText.slice(0, 150) + "..." : fullText);
|
|
138
|
+
}
|
|
139
|
+
// Keyword extraction
|
|
140
|
+
for (const kw of extractKeywords(fullText)) {
|
|
141
|
+
keywordMap[kw] = (keywordMap[kw] || 0) + 1;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// Most frequent keywords (ASO insight)
|
|
145
|
+
const keywordInsights = Object.entries(keywordMap)
|
|
146
|
+
.sort((a, b) => b[1] - a[1])
|
|
147
|
+
.slice(0, 20)
|
|
148
|
+
.map(([keyword, count]) => ({ keyword, count }));
|
|
149
|
+
// Rating distribution
|
|
150
|
+
const ratingDist = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 };
|
|
151
|
+
for (const review of allReviews) {
|
|
152
|
+
const score = review.score || review.rating;
|
|
153
|
+
if (score >= 1 && score <= 5) {
|
|
154
|
+
ratingDist[Math.round(score)]++;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const total = allReviews.length;
|
|
158
|
+
const result = {
|
|
159
|
+
appId,
|
|
160
|
+
appTitle: app.title,
|
|
161
|
+
country,
|
|
162
|
+
totalReviewed: total,
|
|
163
|
+
sentiment: {
|
|
164
|
+
positive,
|
|
165
|
+
negative,
|
|
166
|
+
neutral,
|
|
167
|
+
positivePercent: Math.round((positive / total) * 100),
|
|
168
|
+
negativePercent: Math.round((negative / total) * 100),
|
|
169
|
+
neutralPercent: Math.round((neutral / total) * 100),
|
|
170
|
+
},
|
|
171
|
+
ratingDistribution: ratingDist,
|
|
172
|
+
topComplaints: complaints.slice(0, 10),
|
|
173
|
+
featureRequests: featureRequests.slice(0, 10),
|
|
174
|
+
keywordInsights,
|
|
175
|
+
};
|
|
176
|
+
const resultText = JSON.stringify(result, null, 2);
|
|
177
|
+
setCache(cacheKey, resultText, CACHE_TTL.REVIEWS);
|
|
178
|
+
return { content: [{ type: "text", text: resultText }] };
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
return {
|
|
182
|
+
content: [{ type: "text", text: `Error: ${error.message}` }],
|
|
183
|
+
isError: true,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=analyze-reviews.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-reviews.js","sourceRoot":"","sources":["../../src/tools/analyze-reviews.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clear-cache.d.ts","sourceRoot":"","sources":["../../src/tools/clear-cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,QAmCnD"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { clearCache, getCacheStats } from "../cache/sqlite-cache.js";
|
|
2
|
+
export function registerClearCache(server) {
|
|
3
|
+
server.tool("clear_cache", "Clears the local ASO data cache. Use when you want fresh data from the App Store instead of cached results. Returns cache stats before and after clearing.", {}, async () => {
|
|
4
|
+
try {
|
|
5
|
+
const before = getCacheStats();
|
|
6
|
+
clearCache();
|
|
7
|
+
const after = getCacheStats();
|
|
8
|
+
const result = {
|
|
9
|
+
status: "cleared",
|
|
10
|
+
before: {
|
|
11
|
+
totalEntries: before.totalEntries,
|
|
12
|
+
expiredEntries: before.expiredEntries,
|
|
13
|
+
},
|
|
14
|
+
after: {
|
|
15
|
+
totalEntries: after.totalEntries,
|
|
16
|
+
},
|
|
17
|
+
entriesRemoved: before.totalEntries - after.totalEntries,
|
|
18
|
+
dbPath: before.dbPath,
|
|
19
|
+
};
|
|
20
|
+
return {
|
|
21
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
return {
|
|
26
|
+
content: [{ type: "text", text: `Error: ${error.message}` }],
|
|
27
|
+
isError: true,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=clear-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clear-cache.js","sourceRoot":"","sources":["../../src/tools/clear-cache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAErE,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,MAAM,CAAC,IAAI,CACT,aAAa,EACb,4JAA4J,EAC5J,EAAE,EACF,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;YAC/B,UAAU,EAAE,CAAC;YACb,MAAM,KAAK,GAAG,aAAa,EAAE,CAAC;YAE9B,MAAM,MAAM,GAAG;gBACb,MAAM,EAAE,SAAS;gBACjB,MAAM,EAAE;oBACN,YAAY,EAAE,MAAM,CAAC,YAAY;oBACjC,cAAc,EAAE,MAAM,CAAC,cAAc;iBACtC;gBACD,KAAK,EAAE;oBACL,YAAY,EAAE,KAAK,CAAC,YAAY;iBACjC;gBACD,cAAc,EAAE,MAAM,CAAC,YAAY,GAAG,KAAK,CAAC,YAAY;gBACxD,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB,CAAC;YAEF,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aAC5E,CAAC;QACJ,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,UAAU,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;gBACrE,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect-get-app.d.ts","sourceRoot":"","sources":["../../src/tools/connect-get-app.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,QA2DtD"}
|