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.
Files changed (119) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +227 -0
  3. package/build/cache/sqlite-cache.d.ts +10 -0
  4. package/build/cache/sqlite-cache.d.ts.map +1 -0
  5. package/build/cache/sqlite-cache.js +51 -0
  6. package/build/cache/sqlite-cache.js.map +1 -0
  7. package/build/data-sources/app-store-connect.d.ts +12 -0
  8. package/build/data-sources/app-store-connect.d.ts.map +1 -0
  9. package/build/data-sources/app-store-connect.js +415 -0
  10. package/build/data-sources/app-store-connect.js.map +1 -0
  11. package/build/data-sources/app-store.d.ts +7 -0
  12. package/build/data-sources/app-store.d.ts.map +1 -0
  13. package/build/data-sources/app-store.js +28 -0
  14. package/build/data-sources/app-store.js.map +1 -0
  15. package/build/data-sources/aso-scoring.d.ts +15 -0
  16. package/build/data-sources/aso-scoring.d.ts.map +1 -0
  17. package/build/data-sources/aso-scoring.js +140 -0
  18. package/build/data-sources/aso-scoring.js.map +1 -0
  19. package/build/data-sources/custom-scoring.d.ts +52 -0
  20. package/build/data-sources/custom-scoring.d.ts.map +1 -0
  21. package/build/data-sources/custom-scoring.js +83 -0
  22. package/build/data-sources/custom-scoring.js.map +1 -0
  23. package/build/server.d.ts +3 -0
  24. package/build/server.d.ts.map +1 -0
  25. package/build/server.js +69 -0
  26. package/build/server.js.map +1 -0
  27. package/build/tools/analyze-competitors.d.ts +3 -0
  28. package/build/tools/analyze-competitors.d.ts.map +1 -0
  29. package/build/tools/analyze-competitors.js +112 -0
  30. package/build/tools/analyze-competitors.js.map +1 -0
  31. package/build/tools/analyze-reviews.d.ts +3 -0
  32. package/build/tools/analyze-reviews.d.ts.map +1 -0
  33. package/build/tools/analyze-reviews.js +188 -0
  34. package/build/tools/analyze-reviews.js.map +1 -0
  35. package/build/tools/clear-cache.d.ts +3 -0
  36. package/build/tools/clear-cache.d.ts.map +1 -0
  37. package/build/tools/clear-cache.js +32 -0
  38. package/build/tools/clear-cache.js.map +1 -0
  39. package/build/tools/connect-get-app.d.ts +3 -0
  40. package/build/tools/connect-get-app.d.ts.map +1 -0
  41. package/build/tools/connect-get-app.js +56 -0
  42. package/build/tools/connect-get-app.js.map +1 -0
  43. package/build/tools/connect-get-metadata.d.ts +3 -0
  44. package/build/tools/connect-get-metadata.d.ts.map +1 -0
  45. package/build/tools/connect-get-metadata.js +73 -0
  46. package/build/tools/connect-get-metadata.js.map +1 -0
  47. package/build/tools/connect-list-localizations.d.ts +3 -0
  48. package/build/tools/connect-list-localizations.d.ts.map +1 -0
  49. package/build/tools/connect-list-localizations.js +55 -0
  50. package/build/tools/connect-list-localizations.js.map +1 -0
  51. package/build/tools/connect-setup.d.ts +3 -0
  52. package/build/tools/connect-setup.d.ts.map +1 -0
  53. package/build/tools/connect-setup.js +47 -0
  54. package/build/tools/connect-setup.js.map +1 -0
  55. package/build/tools/connect-update-metadata.d.ts +3 -0
  56. package/build/tools/connect-update-metadata.d.ts.map +1 -0
  57. package/build/tools/connect-update-metadata.js +176 -0
  58. package/build/tools/connect-update-metadata.js.map +1 -0
  59. package/build/tools/discover-keywords.d.ts +3 -0
  60. package/build/tools/discover-keywords.d.ts.map +1 -0
  61. package/build/tools/discover-keywords.js +195 -0
  62. package/build/tools/discover-keywords.js.map +1 -0
  63. package/build/tools/generate-aso-brief.d.ts +3 -0
  64. package/build/tools/generate-aso-brief.d.ts.map +1 -0
  65. package/build/tools/generate-aso-brief.js +295 -0
  66. package/build/tools/generate-aso-brief.js.map +1 -0
  67. package/build/tools/get-app-details.d.ts +3 -0
  68. package/build/tools/get-app-details.d.ts.map +1 -0
  69. package/build/tools/get-app-details.js +89 -0
  70. package/build/tools/get-app-details.js.map +1 -0
  71. package/build/tools/get-aso-report.d.ts +3 -0
  72. package/build/tools/get-aso-report.d.ts.map +1 -0
  73. package/build/tools/get-aso-report.js +168 -0
  74. package/build/tools/get-aso-report.js.map +1 -0
  75. package/build/tools/keyword-gap.d.ts +3 -0
  76. package/build/tools/keyword-gap.d.ts.map +1 -0
  77. package/build/tools/keyword-gap.js +116 -0
  78. package/build/tools/keyword-gap.js.map +1 -0
  79. package/build/tools/localized-keywords.d.ts +3 -0
  80. package/build/tools/localized-keywords.d.ts.map +1 -0
  81. package/build/tools/localized-keywords.js +107 -0
  82. package/build/tools/localized-keywords.js.map +1 -0
  83. package/build/tools/optimize-metadata.d.ts +3 -0
  84. package/build/tools/optimize-metadata.d.ts.map +1 -0
  85. package/build/tools/optimize-metadata.js +156 -0
  86. package/build/tools/optimize-metadata.js.map +1 -0
  87. package/build/tools/search-keywords.d.ts +3 -0
  88. package/build/tools/search-keywords.d.ts.map +1 -0
  89. package/build/tools/search-keywords.js +65 -0
  90. package/build/tools/search-keywords.js.map +1 -0
  91. package/build/tools/suggest-keywords.d.ts +3 -0
  92. package/build/tools/suggest-keywords.d.ts.map +1 -0
  93. package/build/tools/suggest-keywords.js +71 -0
  94. package/build/tools/suggest-keywords.js.map +1 -0
  95. package/build/tools/track-ranking.d.ts +3 -0
  96. package/build/tools/track-ranking.d.ts.map +1 -0
  97. package/build/tools/track-ranking.js +94 -0
  98. package/build/tools/track-ranking.js.map +1 -0
  99. package/build/types/index.d.ts +151 -0
  100. package/build/types/index.d.ts.map +1 -0
  101. package/build/types/index.js +2 -0
  102. package/build/types/index.js.map +1 -0
  103. package/build/utils/constants.d.ts +40 -0
  104. package/build/utils/constants.d.ts.map +1 -0
  105. package/build/utils/constants.js +35 -0
  106. package/build/utils/constants.js.map +1 -0
  107. package/build/utils/formatters.d.ts +9 -0
  108. package/build/utils/formatters.d.ts.map +1 -0
  109. package/build/utils/formatters.js +37 -0
  110. package/build/utils/formatters.js.map +1 -0
  111. package/build/utils/localization.d.ts +7 -0
  112. package/build/utils/localization.d.ts.map +1 -0
  113. package/build/utils/localization.js +63 -0
  114. package/build/utils/localization.js.map +1 -0
  115. package/build/utils/rate-limiter.d.ts +7 -0
  116. package/build/utils/rate-limiter.d.ts.map +1 -0
  117. package/build/utils/rate-limiter.js +23 -0
  118. package/build/utils/rate-limiter.js.map +1 -0
  119. package/package.json +60 -0
@@ -0,0 +1,65 @@
1
+ import { z } from "zod";
2
+ import { getScores } from "../data-sources/aso-scoring.js";
3
+ import { searchApps } from "../data-sources/app-store.js";
4
+ import { getFromCache, setCache } from "../cache/sqlite-cache.js";
5
+ import { CACHE_TTL } from "../utils/constants.js";
6
+ import { formatCompetitionLevel, formatTrafficLevel, generateRecommendation, } from "../utils/formatters.js";
7
+ export function registerSearchKeywords(server) {
8
+ server.tool("search_keywords", "Analyzes traffic score, difficulty score and competitor apps for a keyword on the App Store. The fundamental tool for ASO keyword research.", {
9
+ keyword: z
10
+ .string()
11
+ .describe("Keyword to research (e.g. 'fitness tracker', 'photo editor')"),
12
+ country: z
13
+ .string()
14
+ .default("tr")
15
+ .describe("Country code (tr, us, de, gb, fr...)"),
16
+ num: z
17
+ .number()
18
+ .default(10)
19
+ .describe("Number of competitor apps to show"),
20
+ }, async ({ keyword, country, num }) => {
21
+ const cacheKey = `search:${keyword}:${country}:${num}`;
22
+ const cached = getFromCache(cacheKey);
23
+ if (cached) {
24
+ return { content: [{ type: "text", text: cached }] };
25
+ }
26
+ try {
27
+ const [scores, topApps] = await Promise.all([
28
+ getScores(keyword, country),
29
+ searchApps(keyword, country, num),
30
+ ]);
31
+ const result = {
32
+ keyword,
33
+ country,
34
+ scores: {
35
+ traffic: scores.traffic,
36
+ difficulty: scores.difficulty,
37
+ },
38
+ topApps: topApps.map((app) => ({
39
+ title: app.title,
40
+ developer: app.developer,
41
+ rating: app.score,
42
+ reviews: app.reviews,
43
+ free: app.free,
44
+ price: app.price,
45
+ url: app.url,
46
+ })),
47
+ analysis: {
48
+ competitionLevel: formatCompetitionLevel(scores.difficulty),
49
+ trafficLevel: formatTrafficLevel(scores.traffic),
50
+ recommendation: generateRecommendation(scores),
51
+ },
52
+ };
53
+ const resultText = JSON.stringify(result, null, 2);
54
+ setCache(cacheKey, resultText, CACHE_TTL.KEYWORD_SCORES);
55
+ return { content: [{ type: "text", text: resultText }] };
56
+ }
57
+ catch (error) {
58
+ return {
59
+ content: [{ type: "text", text: `Error: ${error.message}` }],
60
+ isError: true,
61
+ };
62
+ }
63
+ });
64
+ }
65
+ //# sourceMappingURL=search-keywords.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-keywords.js","sourceRoot":"","sources":["../../src/tools/search-keywords.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerSuggestKeywords(server: McpServer): void;
3
+ //# sourceMappingURL=suggest-keywords.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suggest-keywords.d.ts","sourceRoot":"","sources":["../../src/tools/suggest-keywords.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,QAiFxD"}
@@ -0,0 +1,71 @@
1
+ import { z } from "zod";
2
+ import { suggestKeywords, batchGetScores } from "../data-sources/aso-scoring.js";
3
+ import { getFromCache, setCache } from "../cache/sqlite-cache.js";
4
+ import { CACHE_TTL } from "../utils/constants.js";
5
+ export function registerSuggestKeywords(server) {
6
+ server.tool("suggest_keywords", "Generates keyword suggestions using different strategies for a given app ID. Provides category-based, similar apps-based, or competition-based keyword recommendations.", {
7
+ appId: z
8
+ .string()
9
+ .describe("App Store app ID (e.g. 'com.spotify.client' or '324684580')"),
10
+ strategy: z
11
+ .enum(["category", "similar", "competition", "all"])
12
+ .default("all")
13
+ .describe("Keyword suggestion strategy"),
14
+ country: z
15
+ .string()
16
+ .default("tr")
17
+ .describe("Country code (tr, us, de, gb, fr...)"),
18
+ num: z
19
+ .number()
20
+ .default(20)
21
+ .describe("Number of keywords to suggest per strategy"),
22
+ }, async ({ appId, strategy, country, num }) => {
23
+ const cacheKey = `suggest:${appId}:${strategy}:${country}:${num}`;
24
+ const cached = getFromCache(cacheKey);
25
+ if (cached) {
26
+ return { content: [{ type: "text", text: cached }] };
27
+ }
28
+ try {
29
+ const strategies = strategy === "all"
30
+ ? ["category", "similar", "competition"]
31
+ : [strategy];
32
+ const allKeywords = {};
33
+ for (const s of strategies) {
34
+ try {
35
+ const keywords = await suggestKeywords(appId, s, country, num);
36
+ allKeywords[s] = keywords;
37
+ }
38
+ catch {
39
+ allKeywords[s] = [];
40
+ }
41
+ }
42
+ // Get scores for unique keywords (in parallel)
43
+ const uniqueKeywords = [
44
+ ...new Set(Object.values(allKeywords).flat()),
45
+ ];
46
+ const scoredKeywords = await batchGetScores(uniqueKeywords.slice(0, 30), country);
47
+ // Sort by traffic
48
+ scoredKeywords.sort((a, b) => b.traffic - a.traffic);
49
+ const result = {
50
+ appId,
51
+ country,
52
+ strategies: allKeywords,
53
+ scoredKeywords,
54
+ totalUniqueKeywords: uniqueKeywords.length,
55
+ topOpportunities: scoredKeywords
56
+ .filter((k) => k.traffic > 4 && k.difficulty < 6)
57
+ .slice(0, 10),
58
+ };
59
+ const resultText = JSON.stringify(result, null, 2);
60
+ setCache(cacheKey, resultText, CACHE_TTL.SUGGESTIONS);
61
+ return { content: [{ type: "text", text: resultText }] };
62
+ }
63
+ catch (error) {
64
+ return {
65
+ content: [{ type: "text", text: `Error: ${error.message}` }],
66
+ isError: true,
67
+ };
68
+ }
69
+ });
70
+ }
71
+ //# sourceMappingURL=suggest-keywords.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suggest-keywords.js","sourceRoot":"","sources":["../../src/tools/suggest-keywords.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerTrackRanking(server: McpServer): void;
3
+ //# sourceMappingURL=track-ranking.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"track-ranking.d.ts","sourceRoot":"","sources":["../../src/tools/track-ranking.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,QA2GrD"}
@@ -0,0 +1,94 @@
1
+ import { z } from "zod";
2
+ import { searchApps } from "../data-sources/app-store.js";
3
+ import { getFromCache, setCache } from "../cache/sqlite-cache.js";
4
+ import { CACHE_TTL } from "../utils/constants.js";
5
+ export function registerTrackRanking(server) {
6
+ server.tool("track_ranking", "Finds an app's ranking position for specific keywords. Shows the app's position within the top 100 results for each keyword.", {
7
+ appId: z
8
+ .string()
9
+ .describe("App Store app ID or bundle ID (e.g. 'com.spotify.client')"),
10
+ keywords: z
11
+ .array(z.string())
12
+ .describe("List of keywords to track"),
13
+ country: z
14
+ .string()
15
+ .default("tr")
16
+ .describe("Country code"),
17
+ }, async ({ appId, keywords, country }) => {
18
+ const cacheKey = `ranking:${appId}:${keywords.join(",")}:${country}`;
19
+ const cached = getFromCache(cacheKey);
20
+ if (cached) {
21
+ return { content: [{ type: "text", text: cached }] };
22
+ }
23
+ try {
24
+ const rankings = [];
25
+ const normalizedAppId = appId.toLowerCase();
26
+ for (const keyword of keywords.slice(0, 20)) {
27
+ try {
28
+ const results = await searchApps(keyword, country, 100);
29
+ // Find the app's position
30
+ let position = null;
31
+ for (let i = 0; i < results.length; i++) {
32
+ const result = results[i];
33
+ const resultAppId = (result.appId || "").toLowerCase();
34
+ const resultId = String(result.id || "");
35
+ if (resultAppId === normalizedAppId ||
36
+ resultId === appId ||
37
+ resultAppId.includes(normalizedAppId) ||
38
+ normalizedAppId.includes(resultAppId)) {
39
+ position = i + 1;
40
+ break;
41
+ }
42
+ }
43
+ const topResult = results[0];
44
+ rankings.push({
45
+ keyword,
46
+ position,
47
+ topApp: topResult?.title || "Unknown",
48
+ totalResults: results.length,
49
+ });
50
+ }
51
+ catch {
52
+ rankings.push({
53
+ keyword,
54
+ position: null,
55
+ topApp: "Error",
56
+ totalResults: 0,
57
+ });
58
+ }
59
+ }
60
+ // Summary
61
+ const found = rankings.filter((r) => r.position !== null);
62
+ const top10 = found.filter((r) => r.position <= 10);
63
+ const top50 = found.filter((r) => r.position <= 50);
64
+ const result = {
65
+ appId,
66
+ country,
67
+ totalKeywords: keywords.length,
68
+ rankings,
69
+ summary: {
70
+ rankedKeywords: found.length,
71
+ notRanked: rankings.length - found.length,
72
+ top10Count: top10.length,
73
+ top50Count: top50.length,
74
+ bestPosition: found.length > 0
75
+ ? Math.min(...found.map((r) => r.position))
76
+ : null,
77
+ bestKeyword: found.length > 0
78
+ ? found.sort((a, b) => a.position - b.position)[0].keyword
79
+ : null,
80
+ },
81
+ };
82
+ const resultText = JSON.stringify(result, null, 2);
83
+ setCache(cacheKey, resultText, CACHE_TTL.SEARCH_RESULTS);
84
+ return { content: [{ type: "text", text: resultText }] };
85
+ }
86
+ catch (error) {
87
+ return {
88
+ content: [{ type: "text", text: `Error: ${error.message}` }],
89
+ isError: true,
90
+ };
91
+ }
92
+ });
93
+ }
94
+ //# sourceMappingURL=track-ranking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"track-ranking.js","sourceRoot":"","sources":["../../src/tools/track-ranking.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,151 @@
1
+ export interface KeywordScore {
2
+ keyword: string;
3
+ traffic: number;
4
+ difficulty: number;
5
+ }
6
+ export interface AppDetails {
7
+ id: number;
8
+ appId: string;
9
+ title: string;
10
+ url: string;
11
+ description: string;
12
+ developer: string;
13
+ developerId: string;
14
+ score: number;
15
+ reviews: number;
16
+ ratings: number;
17
+ histogram: Record<string, number>;
18
+ price: number;
19
+ free: boolean;
20
+ currency: string;
21
+ genre: string;
22
+ genreId: string;
23
+ icon: string;
24
+ released: string;
25
+ updated: string;
26
+ version: string;
27
+ size: string;
28
+ }
29
+ export interface CompetitorAnalysis {
30
+ keyword: string;
31
+ country: string;
32
+ apps: CompetitorApp[];
33
+ keywordGap: string[];
34
+ commonKeywords: string[];
35
+ metrics: {
36
+ avgRating: number;
37
+ avgReviews: number;
38
+ freePercentage: number;
39
+ topDevelopers: string[];
40
+ };
41
+ }
42
+ export interface CompetitorApp {
43
+ title: string;
44
+ developer: string;
45
+ rating: number;
46
+ reviews: number;
47
+ free: boolean;
48
+ price: number;
49
+ url: string;
50
+ titleKeywords: string[];
51
+ }
52
+ export interface MetadataOptimization {
53
+ current: {
54
+ title: string;
55
+ titleLength: number;
56
+ subtitle?: string;
57
+ subtitleLength?: number;
58
+ };
59
+ suggested: {
60
+ title: string;
61
+ titleLength: number;
62
+ subtitle: string;
63
+ subtitleLength: number;
64
+ keywordField: string;
65
+ keywordFieldLength: number;
66
+ };
67
+ warnings: string[];
68
+ characterLimits: {
69
+ title: {
70
+ used: number;
71
+ max: 30;
72
+ };
73
+ subtitle: {
74
+ used: number;
75
+ max: 30;
76
+ };
77
+ keywords: {
78
+ used: number;
79
+ max: 100;
80
+ };
81
+ };
82
+ }
83
+ export interface ReviewAnalysis {
84
+ appId: number;
85
+ totalReviewed: number;
86
+ sentiment: {
87
+ positive: number;
88
+ negative: number;
89
+ neutral: number;
90
+ };
91
+ topComplaints: string[];
92
+ featureRequests: string[];
93
+ keywordInsights: string[];
94
+ }
95
+ export interface CacheEntry {
96
+ key: string;
97
+ value: string;
98
+ expires_at: number;
99
+ created_at: number;
100
+ }
101
+ export interface ConnectConfig {
102
+ issuerId: string;
103
+ apiKeyId: string;
104
+ privateKeyPath: string;
105
+ }
106
+ export interface ConnectAppInfo {
107
+ id: string;
108
+ bundleId: string;
109
+ name: string;
110
+ primaryLocale: string;
111
+ versionId: string | null;
112
+ versionState: string | null;
113
+ }
114
+ export interface ConnectLocalization {
115
+ locale: string;
116
+ subtitle: string | null;
117
+ subtitleLength: number;
118
+ keywords: string | null;
119
+ keywordsLength: number;
120
+ description: string | null;
121
+ descriptionLength: number;
122
+ promotionalText: string | null;
123
+ promotionalTextLength: number;
124
+ whatsNew: string | null;
125
+ whatsNewLength: number;
126
+ supportUrl: string | null;
127
+ marketingUrl: string | null;
128
+ appInfoLocalizationId: string | null;
129
+ versionLocalizationId: string | null;
130
+ }
131
+ export interface ConnectLocalizationSummary {
132
+ locale: string;
133
+ hasSubtitle: boolean;
134
+ hasKeywords: boolean;
135
+ hasDescription: boolean;
136
+ hasPromotionalText: boolean;
137
+ hasWhatsNew: boolean;
138
+ appInfoLocalizationId: string | null;
139
+ versionLocalizationId: string | null;
140
+ }
141
+ export interface ConnectMetadataUpdate {
142
+ name?: string;
143
+ subtitle?: string;
144
+ keywords?: string;
145
+ description?: string;
146
+ promotionalText?: string;
147
+ whatsNew?: string;
148
+ supportUrl?: string;
149
+ marketingUrl?: string;
150
+ }
151
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,40 @@
1
+ export declare const CHAR_LIMITS: {
2
+ readonly TITLE: 30;
3
+ readonly SUBTITLE: 30;
4
+ readonly KEYWORD_FIELD: 100;
5
+ readonly DESCRIPTION: 4000;
6
+ readonly PROMOTIONAL_TEXT: 170;
7
+ readonly WHATS_NEW: 4000;
8
+ };
9
+ export declare const CACHE_TTL: {
10
+ readonly KEYWORD_SCORES: 3600;
11
+ readonly APP_DETAILS: 21600;
12
+ readonly SEARCH_RESULTS: 3600;
13
+ readonly REVIEWS: 86400;
14
+ readonly SIMILAR_APPS: 86400;
15
+ readonly VERSION_HISTORY: 604800;
16
+ readonly SUGGESTIONS: 3600;
17
+ readonly CONNECT_APP: 1800;
18
+ readonly CONNECT_METADATA: 300;
19
+ readonly CONNECT_LOCALIZATIONS: 600;
20
+ };
21
+ export declare const RATE_LIMITS: {
22
+ readonly "app-store-scraper": {
23
+ readonly maxRequests: 20;
24
+ readonly windowMs: 60000;
25
+ };
26
+ readonly "aso-scores": {
27
+ readonly maxRequests: 10;
28
+ readonly windowMs: 60000;
29
+ };
30
+ readonly "apple-search-ads": {
31
+ readonly maxRequests: 100;
32
+ readonly windowMs: 3600000;
33
+ };
34
+ readonly "app-store-connect": {
35
+ readonly maxRequests: 200;
36
+ readonly windowMs: 60000;
37
+ };
38
+ };
39
+ export declare const POPULAR_COUNTRIES: readonly ["tr", "us", "gb", "de", "fr", "es", "it", "nl", "br", "jp", "kr", "cn", "au", "ca", "mx", "ru", "in", "sa", "ae", "se"];
40
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/utils/constants.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,WAAW;;;;;;;CAOd,CAAC;AAGX,eAAO,MAAM,SAAS;;;;;;;;;;;CAWZ,CAAC;AAGX,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;CAKd,CAAC;AAGX,eAAO,MAAM,iBAAiB,mIAGpB,CAAC"}
@@ -0,0 +1,35 @@
1
+ // App Store metadata character limits
2
+ export const CHAR_LIMITS = {
3
+ TITLE: 30,
4
+ SUBTITLE: 30,
5
+ KEYWORD_FIELD: 100,
6
+ DESCRIPTION: 4000,
7
+ PROMOTIONAL_TEXT: 170,
8
+ WHATS_NEW: 4000,
9
+ };
10
+ // Cache TTL values (seconds)
11
+ export const CACHE_TTL = {
12
+ KEYWORD_SCORES: 3600, // 1 hour
13
+ APP_DETAILS: 21600, // 6 hours
14
+ SEARCH_RESULTS: 3600, // 1 hour
15
+ REVIEWS: 86400, // 24 hours
16
+ SIMILAR_APPS: 86400, // 24 hours
17
+ VERSION_HISTORY: 604800, // 7 days
18
+ SUGGESTIONS: 3600, // 1 hour
19
+ CONNECT_APP: 1800, // 30 minutes
20
+ CONNECT_METADATA: 300, // 5 minutes
21
+ CONNECT_LOCALIZATIONS: 600, // 10 minutes
22
+ };
23
+ // Rate limit settings
24
+ export const RATE_LIMITS = {
25
+ "app-store-scraper": { maxRequests: 20, windowMs: 60_000 },
26
+ "aso-scores": { maxRequests: 10, windowMs: 60_000 },
27
+ "apple-search-ads": { maxRequests: 100, windowMs: 3_600_000 },
28
+ "app-store-connect": { maxRequests: 200, windowMs: 60_000 },
29
+ };
30
+ // Supported countries (most used)
31
+ export const POPULAR_COUNTRIES = [
32
+ "tr", "us", "gb", "de", "fr", "es", "it", "nl", "br", "jp",
33
+ "kr", "cn", "au", "ca", "mx", "ru", "in", "sa", "ae", "se",
34
+ ];
35
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/utils/constants.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,KAAK,EAAE,EAAE;IACT,QAAQ,EAAE,EAAE;IACZ,aAAa,EAAE,GAAG;IAClB,WAAW,EAAE,IAAI;IACjB,gBAAgB,EAAE,GAAG;IACrB,SAAS,EAAE,IAAI;CACP,CAAC;AAEX,6BAA6B;AAC7B,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,cAAc,EAAE,IAAI,EAAQ,SAAS;IACrC,WAAW,EAAE,KAAK,EAAU,UAAU;IACtC,cAAc,EAAE,IAAI,EAAQ,SAAS;IACrC,OAAO,EAAE,KAAK,EAAc,WAAW;IACvC,YAAY,EAAE,KAAK,EAAS,WAAW;IACvC,eAAe,EAAE,MAAM,EAAK,SAAS;IACrC,WAAW,EAAE,IAAI,EAAW,SAAS;IACrC,WAAW,EAAE,IAAI,EAAW,aAAa;IACzC,gBAAgB,EAAE,GAAG,EAAO,YAAY;IACxC,qBAAqB,EAAE,GAAG,EAAE,aAAa;CACjC,CAAC;AAEX,sBAAsB;AACtB,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,mBAAmB,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;IAC1D,YAAY,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE;IACnD,kBAAkB,EAAE,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE;IAC7D,mBAAmB,EAAE,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE;CACnD,CAAC;AAEX,kCAAkC;AAClC,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;IAC1D,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;CAClD,CAAC"}
@@ -0,0 +1,9 @@
1
+ export declare function formatScore(score: number): string;
2
+ export declare function formatCompetitionLevel(difficulty: number): string;
3
+ export declare function formatTrafficLevel(traffic: number): string;
4
+ export declare function generateRecommendation(scores: {
5
+ traffic: number;
6
+ difficulty: number;
7
+ }): string;
8
+ export declare function truncateText(text: string, maxLength: number): string;
9
+ //# sourceMappingURL=formatters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatters.d.ts","sourceRoot":"","sources":["../../src/utils/formatters.ts"],"names":[],"mappings":"AAAA,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAIjE;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAI1D;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,MAAM,CAUT;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAGpE"}
@@ -0,0 +1,37 @@
1
+ export function formatScore(score) {
2
+ return score.toFixed(1);
3
+ }
4
+ export function formatCompetitionLevel(difficulty) {
5
+ if (difficulty > 7)
6
+ return "High";
7
+ if (difficulty > 4)
8
+ return "Medium";
9
+ return "Low";
10
+ }
11
+ export function formatTrafficLevel(traffic) {
12
+ if (traffic > 7)
13
+ return "High";
14
+ if (traffic > 4)
15
+ return "Medium";
16
+ return "Low";
17
+ }
18
+ export function generateRecommendation(scores) {
19
+ if (scores.traffic > 6 && scores.difficulty < 5) {
20
+ return "Excellent opportunity! High traffic, low competition.";
21
+ }
22
+ else if (scores.traffic > 6 && scores.difficulty > 6) {
23
+ return "High traffic but competition is also high. Try long-tail variations.";
24
+ }
25
+ else if (scores.traffic < 4 && scores.difficulty < 4) {
26
+ return "Low traffic, low competition. Niche keyword — support with additional keywords.";
27
+ }
28
+ else {
29
+ return "Low traffic, high competition. Consider alternative keywords.";
30
+ }
31
+ }
32
+ export function truncateText(text, maxLength) {
33
+ if (text.length <= maxLength)
34
+ return text;
35
+ return text.slice(0, maxLength - 3) + "...";
36
+ }
37
+ //# sourceMappingURL=formatters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatters.js","sourceRoot":"","sources":["../../src/utils/formatters.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,UAAkB;IACvD,IAAI,UAAU,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IAClC,IAAI,UAAU,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAC;IACpC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,IAAI,OAAO,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IAC/B,IAAI,OAAO,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAC;IACjC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,MAGtC;IACC,IAAI,MAAM,CAAC,OAAO,GAAG,CAAC,IAAI,MAAM,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;QAChD,OAAO,uDAAuD,CAAC;IACjE,CAAC;SAAM,IAAI,MAAM,CAAC,OAAO,GAAG,CAAC,IAAI,MAAM,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;QACvD,OAAO,sEAAsE,CAAC;IAChF,CAAC;SAAM,IAAI,MAAM,CAAC,OAAO,GAAG,CAAC,IAAI,MAAM,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;QACvD,OAAO,iFAAiF,CAAC;IAC3F,CAAC;SAAM,CAAC;QACN,OAAO,+DAA+D,CAAC;IACzE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,SAAiB;IAC1D,IAAI,IAAI,CAAC,MAAM,IAAI,SAAS;QAAE,OAAO,IAAI,CAAC;IAC1C,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,7 @@
1
+ export declare const COUNTRY_NAMES: Record<string, string>;
2
+ export declare function getCountryName(code: string): string;
3
+ export declare function isValidCountryCode(code: string): boolean;
4
+ export declare const COUNTRY_TO_LOCALE: Record<string, string>;
5
+ export declare function countryToLocale(code: string): string;
6
+ export declare function localeToCountry(locale: string): string;
7
+ //# sourceMappingURL=localization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"localization.d.ts","sourceRoot":"","sources":["../../src/utils/localization.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAqBhD,CAAC;AAEF,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAExD;AAID,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAqBpD,CAAC;AAMF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMpD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtD"}
@@ -0,0 +1,63 @@
1
+ export const COUNTRY_NAMES = {
2
+ tr: "Turkey",
3
+ us: "United States",
4
+ gb: "United Kingdom",
5
+ de: "Germany",
6
+ fr: "France",
7
+ es: "Spain",
8
+ it: "Italy",
9
+ nl: "Netherlands",
10
+ br: "Brazil",
11
+ jp: "Japan",
12
+ kr: "South Korea",
13
+ cn: "China",
14
+ au: "Australia",
15
+ ca: "Canada",
16
+ mx: "Mexico",
17
+ ru: "Russia",
18
+ in: "India",
19
+ sa: "Saudi Arabia",
20
+ ae: "United Arab Emirates",
21
+ se: "Sweden",
22
+ };
23
+ export function getCountryName(code) {
24
+ return COUNTRY_NAMES[code.toLowerCase()] ?? code.toUpperCase();
25
+ }
26
+ export function isValidCountryCode(code) {
27
+ return /^[a-z]{2}$/i.test(code);
28
+ }
29
+ // ─── App Store Connect Locale Mapping ───
30
+ export const COUNTRY_TO_LOCALE = {
31
+ tr: "tr",
32
+ us: "en-US",
33
+ gb: "en-GB",
34
+ au: "en-AU",
35
+ ca: "en-CA",
36
+ de: "de-DE",
37
+ fr: "fr-FR",
38
+ es: "es-ES",
39
+ it: "it",
40
+ nl: "nl-NL",
41
+ br: "pt-BR",
42
+ jp: "ja",
43
+ kr: "ko",
44
+ cn: "zh-Hans",
45
+ ru: "ru",
46
+ in: "hi",
47
+ sa: "ar-SA",
48
+ ae: "ar-SA",
49
+ se: "sv",
50
+ mx: "es-MX",
51
+ };
52
+ const LOCALE_TO_COUNTRY = Object.fromEntries(Object.entries(COUNTRY_TO_LOCALE).map(([k, v]) => [v, k]));
53
+ export function countryToLocale(code) {
54
+ // If it already looks like an Apple locale (contains dash or is longer than 2 chars), return as-is
55
+ if (code.includes("-") || code.length > 2) {
56
+ return code;
57
+ }
58
+ return COUNTRY_TO_LOCALE[code.toLowerCase()] ?? code;
59
+ }
60
+ export function localeToCountry(locale) {
61
+ return LOCALE_TO_COUNTRY[locale] ?? locale.toLowerCase();
62
+ }
63
+ //# sourceMappingURL=localization.js.map