pabal-store-api-mcp 1.1.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 (111) hide show
  1. package/README.md +95 -0
  2. package/bin/pabal-mcp.js +6 -0
  3. package/dist/src/core/clients/app-store-factory.d.ts +29 -0
  4. package/dist/src/core/clients/app-store-factory.js +72 -0
  5. package/dist/src/core/clients/client-factory-helpers.d.ts +7 -0
  6. package/dist/src/core/clients/client-factory-helpers.js +10 -0
  7. package/dist/src/core/clients/google-play-factory.d.ts +29 -0
  8. package/dist/src/core/clients/google-play-factory.js +72 -0
  9. package/dist/src/core/clients/types.d.ts +8 -0
  10. package/dist/src/core/clients/types.js +1 -0
  11. package/dist/src/core/helpers/formatters.d.ts +3 -0
  12. package/dist/src/core/helpers/formatters.js +38 -0
  13. package/dist/src/core/helpers/registration.d.ts +21 -0
  14. package/dist/src/core/helpers/registration.js +21 -0
  15. package/dist/src/core/helpers/translate-release-notes.d.ts +46 -0
  16. package/dist/src/core/helpers/translate-release-notes.js +87 -0
  17. package/dist/src/core/services/app-resolution-service.d.ts +14 -0
  18. package/dist/src/core/services/app-resolution-service.js +35 -0
  19. package/dist/src/core/services/app-store-service.d.ts +41 -0
  20. package/dist/src/core/services/app-store-service.js +266 -0
  21. package/dist/src/core/services/google-play-service.d.ts +36 -0
  22. package/dist/src/core/services/google-play-service.js +203 -0
  23. package/dist/src/core/services/service-helpers.d.ts +15 -0
  24. package/dist/src/core/services/service-helpers.js +31 -0
  25. package/dist/src/core/services/types.d.ts +81 -0
  26. package/dist/src/core/services/types.js +1 -0
  27. package/dist/src/core/workflows/version-info.d.ts +29 -0
  28. package/dist/src/core/workflows/version-info.js +100 -0
  29. package/dist/src/index.d.ts +10 -0
  30. package/dist/src/index.js +279 -0
  31. package/dist/src/packages/common/errors/app-error.d.ts +39 -0
  32. package/dist/src/packages/common/errors/app-error.js +134 -0
  33. package/dist/src/packages/common/errors/error-codes.d.ts +63 -0
  34. package/dist/src/packages/common/errors/error-codes.js +71 -0
  35. package/dist/src/packages/common/errors/status-codes.d.ts +10 -0
  36. package/dist/src/packages/common/errors/status-codes.js +9 -0
  37. package/dist/src/packages/configs/aso-config/constants.d.ts +14 -0
  38. package/dist/src/packages/configs/aso-config/constants.js +102 -0
  39. package/dist/src/packages/configs/aso-config/locale-guards.d.ts +3 -0
  40. package/dist/src/packages/configs/aso-config/locale-guards.js +7 -0
  41. package/dist/src/packages/configs/aso-config/store.d.ts +11 -0
  42. package/dist/src/packages/configs/aso-config/store.js +11 -0
  43. package/dist/src/packages/configs/aso-config/types.d.ts +98 -0
  44. package/dist/src/packages/configs/aso-config/types.js +2 -0
  45. package/dist/src/packages/configs/aso-config/utils.d.ts +43 -0
  46. package/dist/src/packages/configs/aso-config/utils.js +223 -0
  47. package/dist/src/packages/configs/secrets-config/config.d.ts +12 -0
  48. package/dist/src/packages/configs/secrets-config/config.js +187 -0
  49. package/dist/src/packages/configs/secrets-config/constants.d.ts +1 -0
  50. package/dist/src/packages/configs/secrets-config/constants.js +1 -0
  51. package/dist/src/packages/configs/secrets-config/errors.d.ts +9 -0
  52. package/dist/src/packages/configs/secrets-config/errors.js +15 -0
  53. package/dist/src/packages/configs/secrets-config/registered-apps.d.ts +52 -0
  54. package/dist/src/packages/configs/secrets-config/registered-apps.js +108 -0
  55. package/dist/src/packages/configs/secrets-config/schemas.d.ts +21 -0
  56. package/dist/src/packages/configs/secrets-config/schemas.js +9 -0
  57. package/dist/src/packages/configs/secrets-config/types.d.ts +8 -0
  58. package/dist/src/packages/configs/secrets-config/types.js +1 -0
  59. package/dist/src/packages/stores/app-store/api-converters.d.ts +26 -0
  60. package/dist/src/packages/stores/app-store/api-converters.js +131 -0
  61. package/dist/src/packages/stores/app-store/api-endpoints.d.ts +33 -0
  62. package/dist/src/packages/stores/app-store/api-endpoints.js +157 -0
  63. package/dist/src/packages/stores/app-store/auth.d.ts +12 -0
  64. package/dist/src/packages/stores/app-store/auth.js +36 -0
  65. package/dist/src/packages/stores/app-store/client.d.ts +78 -0
  66. package/dist/src/packages/stores/app-store/client.js +637 -0
  67. package/dist/src/packages/stores/app-store/constants.d.ts +11 -0
  68. package/dist/src/packages/stores/app-store/constants.js +38 -0
  69. package/dist/src/packages/stores/app-store/generated-types.d.ts +118537 -0
  70. package/dist/src/packages/stores/app-store/generated-types.js +5 -0
  71. package/dist/src/packages/stores/app-store/types.d.ts +39 -0
  72. package/dist/src/packages/stores/app-store/types.js +9 -0
  73. package/dist/src/packages/stores/app-store/verify-auth.d.ts +16 -0
  74. package/dist/src/packages/stores/app-store/verify-auth.js +34 -0
  75. package/dist/src/packages/stores/play-store/api-converters.d.ts +58 -0
  76. package/dist/src/packages/stores/play-store/api-converters.js +209 -0
  77. package/dist/src/packages/stores/play-store/api-endpoints.d.ts +68 -0
  78. package/dist/src/packages/stores/play-store/api-endpoints.js +145 -0
  79. package/dist/src/packages/stores/play-store/client.d.ts +55 -0
  80. package/dist/src/packages/stores/play-store/client.js +628 -0
  81. package/dist/src/packages/stores/play-store/constants.d.ts +10 -0
  82. package/dist/src/packages/stores/play-store/constants.js +17 -0
  83. package/dist/src/packages/stores/play-store/types.d.ts +146 -0
  84. package/dist/src/packages/stores/play-store/types.js +9 -0
  85. package/dist/src/packages/stores/play-store/verify-auth.d.ts +13 -0
  86. package/dist/src/packages/stores/play-store/verify-auth.js +31 -0
  87. package/dist/src/tools/apps/add.d.ts +28 -0
  88. package/dist/src/tools/apps/add.js +307 -0
  89. package/dist/src/tools/apps/init.d.ts +58 -0
  90. package/dist/src/tools/apps/init.js +390 -0
  91. package/dist/src/tools/apps/search.d.ts +33 -0
  92. package/dist/src/tools/apps/search.js +147 -0
  93. package/dist/src/tools/aso/pull.d.ts +22 -0
  94. package/dist/src/tools/aso/pull.js +264 -0
  95. package/dist/src/tools/aso/push.d.ts +23 -0
  96. package/dist/src/tools/aso/push.js +189 -0
  97. package/dist/src/tools/auth/app-store.d.ts +9 -0
  98. package/dist/src/tools/auth/app-store.js +34 -0
  99. package/dist/src/tools/auth/check.d.ts +14 -0
  100. package/dist/src/tools/auth/check.js +50 -0
  101. package/dist/src/tools/auth/play-store.d.ts +9 -0
  102. package/dist/src/tools/auth/play-store.js +30 -0
  103. package/dist/src/tools/release/check-versions.d.ts +14 -0
  104. package/dist/src/tools/release/check-versions.js +65 -0
  105. package/dist/src/tools/release/create.d.ts +23 -0
  106. package/dist/src/tools/release/create.js +128 -0
  107. package/dist/src/tools/release/pull-notes.d.ts +22 -0
  108. package/dist/src/tools/release/pull-notes.js +151 -0
  109. package/dist/src/tools/release/update-notes.d.ts +110 -0
  110. package/dist/src/tools/release/update-notes.js +537 -0
  111. package/package.json +71 -0
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Google Play Console API Types
3
+ *
4
+ * Type definitions for Google Play Store operations.
5
+ * Types are derived from googleapis library types.
6
+ *
7
+ * @see https://developers.google.com/android-publisher
8
+ */
9
+ import type { androidpublisher_v3 } from "googleapis";
10
+ /**
11
+ * Auth type from googleapis
12
+ * Used internally for EditSession
13
+ */
14
+ type AuthType = androidpublisher_v3.Params$Resource$Edits$Insert["auth"];
15
+ /**
16
+ * Schema types from googleapis
17
+ * Re-exported for use across the codebase
18
+ */
19
+ export type AppEdit = androidpublisher_v3.Schema$AppEdit;
20
+ export type AppDetails = androidpublisher_v3.Schema$AppDetails;
21
+ export type Listing = androidpublisher_v3.Schema$Listing;
22
+ export type Image = androidpublisher_v3.Schema$Image;
23
+ export type Track = androidpublisher_v3.Schema$Track;
24
+ export type TrackRelease = androidpublisher_v3.Schema$TrackRelease;
25
+ export type ListingsListResponse = androidpublisher_v3.Schema$ListingsListResponse;
26
+ export type ImagesListResponse = androidpublisher_v3.Schema$ImagesListResponse;
27
+ export type TracksListResponse = androidpublisher_v3.Schema$TracksListResponse;
28
+ export type ImagesUploadResponse = androidpublisher_v3.Schema$ImagesUploadResponse;
29
+ /**
30
+ * Google Play Client Configuration
31
+ * Internal type for client initialization
32
+ */
33
+ export interface GooglePlayClientConfig {
34
+ packageName: string;
35
+ serviceAccountKeyPath?: string;
36
+ serviceAccountKey?: object;
37
+ }
38
+ /**
39
+ * Edit Session
40
+ * Internal helper type that extends AppEdit with auth and packageName
41
+ * for convenience in API calls
42
+ */
43
+ export interface EditSession extends Pick<AppEdit, "id"> {
44
+ auth: AuthType;
45
+ packageName: string;
46
+ editId: string;
47
+ }
48
+ /**
49
+ * Screenshot URLs grouped by device type
50
+ * Internal type for organizing screenshots by device category
51
+ */
52
+ export interface ScreenshotUrls {
53
+ phone: string[];
54
+ tablet7: string[];
55
+ tablet10: string[];
56
+ tv: string[];
57
+ wear: string[];
58
+ }
59
+ /**
60
+ * App Access Information
61
+ * Internal type for app verification results
62
+ */
63
+ export interface AppAccessInfo {
64
+ packageName: string;
65
+ title?: string;
66
+ defaultLanguage?: string;
67
+ supportedLocales?: string[];
68
+ }
69
+ /**
70
+ * Latest Release Information
71
+ * Internal type derived from TrackRelease for convenience
72
+ * Extracts and transforms TrackRelease data for easier consumption
73
+ */
74
+ export interface LatestReleaseInfo {
75
+ versionCodes: number[];
76
+ status?: NonNullable<TrackRelease["status"]>;
77
+ versionName?: string;
78
+ releaseName?: NonNullable<TrackRelease["name"]>;
79
+ releaseDate?: string;
80
+ }
81
+ /**
82
+ * Release Update Result
83
+ * Internal type for tracking release note update operations
84
+ */
85
+ export interface ReleaseUpdateResult {
86
+ updated: string[];
87
+ failed: Array<{
88
+ locale: string;
89
+ error: string;
90
+ }>;
91
+ }
92
+ /**
93
+ * Create Release Options
94
+ * Internal type for creating a new release
95
+ * Based on TrackRelease but with simplified versionCodes (number[])
96
+ */
97
+ export interface CreateReleaseOptions {
98
+ versionCodes: number[];
99
+ releaseName?: NonNullable<TrackRelease["name"]>;
100
+ status?: NonNullable<TrackRelease["status"]>;
101
+ }
102
+ /**
103
+ * Upload Screenshot Options
104
+ * Internal type for screenshot upload operations
105
+ */
106
+ export interface UploadScreenshotOptions {
107
+ imagePath: string;
108
+ imageType: "phoneScreenshots" | "sevenInchScreenshots" | "tenInchScreenshots" | "tvScreenshots" | "wearScreenshots" | "featureGraphic";
109
+ language?: string;
110
+ }
111
+ /**
112
+ * Update Release Notes Options
113
+ * Internal type for updating release notes
114
+ */
115
+ export interface UpdateReleaseNotesOptions {
116
+ releaseNotes: Record<string, string>;
117
+ track?: string;
118
+ }
119
+ /**
120
+ * App Details Data
121
+ * Internal type for app details update operations
122
+ * Based on AppDetails but with optional fields for partial updates
123
+ */
124
+ export interface AppDetailsData {
125
+ contactEmail?: NonNullable<AppDetails["contactEmail"]>;
126
+ contactPhone?: NonNullable<AppDetails["contactPhone"]>;
127
+ contactWebsite?: NonNullable<AppDetails["contactWebsite"]>;
128
+ defaultLanguage?: NonNullable<AppDetails["defaultLanguage"]>;
129
+ }
130
+ export type ImageType = "appImageTypeUnspecified" | "phoneScreenshots" | "sevenInchScreenshots" | "tenInchScreenshots" | "tvScreenshots" | "wearScreenshots" | "icon" | "featureGraphic" | "tvBanner";
131
+ /**
132
+ * Listing Update Request Attributes
133
+ * @see https://developers.google.com/android-publisher/api-ref/rest/v3/edits.listings#Listing
134
+ */
135
+ export type ListingUpdateAttributes = Partial<Pick<androidpublisher_v3.Schema$Listing, "language" | "title" | "shortDescription" | "fullDescription" | "video">>;
136
+ /**
137
+ * App Details Update Request Attributes
138
+ * @see https://developers.google.com/android-publisher/api-ref/rest/v3/edits.details#AppDetails
139
+ */
140
+ export type AppDetailsUpdateAttributes = Partial<Pick<androidpublisher_v3.Schema$AppDetails, "defaultLanguage" | "contactEmail" | "contactPhone" | "contactWebsite">>;
141
+ /**
142
+ * Track Update Request Attributes
143
+ * @see https://developers.google.com/android-publisher/api-ref/rest/v3/edits.tracks#Track
144
+ */
145
+ export type TrackUpdateAttributes = Partial<Pick<androidpublisher_v3.Schema$Track, "track" | "releases">>;
146
+ export {};
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Google Play Console API Types
3
+ *
4
+ * Type definitions for Google Play Store operations.
5
+ * Types are derived from googleapis library types.
6
+ *
7
+ * @see https://developers.google.com/android-publisher
8
+ */
9
+ export {};
@@ -0,0 +1,13 @@
1
+ export interface VerifyPlayStoreAuthResult {
2
+ success: boolean;
3
+ error?: string;
4
+ data?: {
5
+ client_email: string;
6
+ project_id: string;
7
+ };
8
+ }
9
+ /**
10
+ * Verify Google Play Store service account authentication configuration.
11
+ * @returns Authentication verification result
12
+ */
13
+ export declare function verifyPlayStoreAuth(): VerifyPlayStoreAuthResult;
@@ -0,0 +1,31 @@
1
+ import { loadConfig } from "../../../packages/configs/secrets-config/config.js";
2
+ /**
3
+ * Verify Google Play Store service account authentication configuration.
4
+ * @returns Authentication verification result
5
+ */
6
+ export function verifyPlayStoreAuth() {
7
+ try {
8
+ const cfg = loadConfig().playStore;
9
+ if (!cfg) {
10
+ return {
11
+ success: false,
12
+ error: "Play Store configuration not found in ~/.config/pabal-mcp/config.json file.",
13
+ };
14
+ }
15
+ const parsed = JSON.parse(cfg.serviceAccountJson);
16
+ return {
17
+ success: true,
18
+ data: {
19
+ client_email: parsed.client_email,
20
+ project_id: parsed.project_id,
21
+ },
22
+ };
23
+ }
24
+ catch (error) {
25
+ const message = error instanceof Error ? error.message : String(error);
26
+ return {
27
+ success: false,
28
+ error: `Play Store authentication verification failed: ${message}`,
29
+ };
30
+ }
31
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * add-app: Register app by bundleId or packageName
3
+ */
4
+ import { type RegisteredApp } from "../../packages/configs/secrets-config/registered-apps.js";
5
+ interface AddAppOptions {
6
+ /** App identifier (bundleId or packageName) */
7
+ identifier: string;
8
+ /** Custom slug (if not specified, uses last part of identifier) */
9
+ slug?: string;
10
+ /** Target store (default: both - check both stores) */
11
+ store?: "appStore" | "googlePlay" | "both";
12
+ }
13
+ export declare function handleAddApp(options: AddAppOptions): Promise<{
14
+ content: {
15
+ type: "text";
16
+ text: string;
17
+ }[];
18
+ _meta?: undefined;
19
+ } | {
20
+ content: {
21
+ type: "text";
22
+ text: string;
23
+ }[];
24
+ _meta: {
25
+ app: RegisteredApp;
26
+ };
27
+ }>;
28
+ export {};
@@ -0,0 +1,307 @@
1
+ /**
2
+ * add-app: Register app by bundleId or packageName
3
+ */
4
+ import { registerApp, findApp, loadRegisteredApps, saveRegisteredApps, } from "../../packages/configs/secrets-config/registered-apps.js";
5
+ import { toRegisteredAppStoreInfo, toRegisteredGooglePlayInfo, } from "../../core/helpers/registration.js";
6
+ import { AppStoreService } from "../../core/services/app-store-service.js";
7
+ import { GooglePlayService } from "../../core/services/google-play-service.js";
8
+ const appStoreService = new AppStoreService();
9
+ const googlePlayService = new GooglePlayService();
10
+ /**
11
+ * Generate slug (last part of identifier)
12
+ */
13
+ function generateSlug(identifier) {
14
+ const parts = identifier.split(".");
15
+ return parts[parts.length - 1].toLowerCase();
16
+ }
17
+ export async function handleAddApp(options) {
18
+ const { identifier, slug: customSlug, store = "both" } = options;
19
+ console.error(`[MCP] 📱 Adding app: ${identifier} (store: ${store})`);
20
+ if (!identifier) {
21
+ return {
22
+ content: [
23
+ {
24
+ type: "text",
25
+ text: `❌ identifier is required.
26
+
27
+ Usage:
28
+ \`\`\`json
29
+ { "identifier": "com.example.app" }
30
+ { "identifier": "com.example.app", "slug": "myapp" }
31
+ { "identifier": "com.example.app", "store": "googlePlay" }
32
+ \`\`\``,
33
+ },
34
+ ],
35
+ };
36
+ }
37
+ // Check if already registered
38
+ let existing;
39
+ try {
40
+ existing = findApp(identifier);
41
+ }
42
+ catch (error) {
43
+ const message = error instanceof Error ? error.message : String(error);
44
+ return {
45
+ content: [
46
+ {
47
+ type: "text",
48
+ text: `❌ Failed to load registered apps: ${message}`,
49
+ },
50
+ ],
51
+ };
52
+ }
53
+ if (existing) {
54
+ // Update language info for existing apps
55
+ let appsConfig;
56
+ try {
57
+ appsConfig = loadRegisteredApps();
58
+ }
59
+ catch (error) {
60
+ const message = error instanceof Error ? error.message : String(error);
61
+ return {
62
+ content: [
63
+ {
64
+ type: "text",
65
+ text: `❌ Failed to load registered apps: ${message}`,
66
+ },
67
+ ],
68
+ };
69
+ }
70
+ const appIndex = appsConfig.apps.findIndex((a) => a.slug === existing.slug);
71
+ if (appIndex >= 0) {
72
+ let updated = false;
73
+ const updateResults = [];
74
+ // Update App Store language info
75
+ if (store === "both" || store === "appStore") {
76
+ if (existing.appStore) {
77
+ const asResult = await appStoreService.fetchAppInfo(identifier);
78
+ if (asResult.found && asResult.supportedLocales) {
79
+ if (!appsConfig.apps[appIndex].appStore) {
80
+ appsConfig.apps[appIndex].appStore = {
81
+ bundleId: identifier,
82
+ appId: asResult.appId,
83
+ name: asResult.name,
84
+ };
85
+ }
86
+ appsConfig.apps[appIndex].appStore.supportedLocales =
87
+ asResult.supportedLocales;
88
+ updated = true;
89
+ updateResults.push(`🍎 App Store: Updated locales (${asResult.supportedLocales.length})`);
90
+ }
91
+ }
92
+ }
93
+ // Update Google Play language info
94
+ if (store === "both" || store === "googlePlay") {
95
+ if (existing.googlePlay || store === "googlePlay") {
96
+ const gpResult = await googlePlayService.fetchAppInfo(identifier);
97
+ if (gpResult.found && gpResult.supportedLocales) {
98
+ if (!appsConfig.apps[appIndex].googlePlay) {
99
+ appsConfig.apps[appIndex].googlePlay = {
100
+ packageName: identifier,
101
+ name: gpResult.name,
102
+ };
103
+ }
104
+ appsConfig.apps[appIndex].googlePlay.supportedLocales =
105
+ gpResult.supportedLocales;
106
+ if (gpResult.name) {
107
+ appsConfig.apps[appIndex].googlePlay.name = gpResult.name;
108
+ }
109
+ updated = true;
110
+ updateResults.push(`🤖 Google Play: Updated locales (${gpResult.supportedLocales.length})`);
111
+ }
112
+ }
113
+ }
114
+ if (updated) {
115
+ saveRegisteredApps(appsConfig);
116
+ const updatedApp = appsConfig.apps[appIndex];
117
+ const localeInfo = [];
118
+ if (updatedApp.appStore?.supportedLocales &&
119
+ updatedApp.appStore.supportedLocales.length > 0) {
120
+ localeInfo.push(`• App Store locales: ${updatedApp.appStore.supportedLocales.join(", ")}`);
121
+ }
122
+ if (updatedApp.googlePlay?.supportedLocales &&
123
+ updatedApp.googlePlay.supportedLocales.length > 0) {
124
+ localeInfo.push(`• Google Play locales: ${updatedApp.googlePlay.supportedLocales.join(", ")}`);
125
+ }
126
+ return {
127
+ content: [
128
+ {
129
+ type: "text",
130
+ text: `✅ App language info updated
131
+
132
+ • Slug: \`${updatedApp.slug}\`
133
+ • Name: ${updatedApp.name}
134
+ • App Store: ${updatedApp.appStore ? `✅ ${updatedApp.appStore.bundleId}` : "❌"}
135
+ • Google Play: ${updatedApp.googlePlay ? `✅ ${updatedApp.googlePlay.packageName}` : "❌"}
136
+ ${updateResults.length > 0 ? `\n**Updates:**\n${updateResults.map((r) => ` • ${r}`).join("\n")}` : ""}
137
+ ${localeInfo.length > 0 ? `\n**Supported Languages:**\n${localeInfo.map((l) => ` ${l}`).join("\n")}` : ""}`,
138
+ },
139
+ ],
140
+ _meta: { app: updatedApp },
141
+ };
142
+ }
143
+ }
144
+ // If no updates were made, return existing info
145
+ const localeInfo = [];
146
+ if (existing.appStore?.supportedLocales &&
147
+ existing.appStore.supportedLocales.length > 0) {
148
+ localeInfo.push(`• App Store locales: ${existing.appStore.supportedLocales.join(", ")}`);
149
+ }
150
+ if (existing.googlePlay?.supportedLocales &&
151
+ existing.googlePlay.supportedLocales.length > 0) {
152
+ localeInfo.push(`• Google Play locales: ${existing.googlePlay.supportedLocales.join(", ")}`);
153
+ }
154
+ return {
155
+ content: [
156
+ {
157
+ type: "text",
158
+ text: `⏭️ App is already registered.
159
+
160
+ • Slug: \`${existing.slug}\`
161
+ • Name: ${existing.name}
162
+ • App Store: ${existing.appStore ? `✅ ${existing.appStore.bundleId}` : "❌"}
163
+ • Google Play: ${existing.googlePlay ? `✅ ${existing.googlePlay.packageName}` : "❌"}
164
+ ${localeInfo.length > 0 ? `\n**Supported Languages:**\n${localeInfo.map((l) => ` ${l}`).join("\n")}` : ""}`,
165
+ },
166
+ ],
167
+ _meta: { app: existing },
168
+ };
169
+ }
170
+ const slug = customSlug || generateSlug(identifier);
171
+ // Check for slug duplicates
172
+ const slugExists = findApp(slug);
173
+ if (slugExists) {
174
+ return {
175
+ content: [
176
+ {
177
+ type: "text",
178
+ text: `❌ slug "${slug}" is already in use. Please specify a different slug.
179
+
180
+ \`\`\`json
181
+ { "identifier": "${identifier}", "slug": "different-slug" }
182
+ \`\`\``,
183
+ },
184
+ ],
185
+ };
186
+ }
187
+ // Fetch app information by store (언어 정보 포함)
188
+ let appStoreInfo = undefined;
189
+ let googlePlayInfo = undefined;
190
+ let appName = identifier;
191
+ const results = [];
192
+ // Check App Store
193
+ if (store === "both" || store === "appStore") {
194
+ console.error(`[MCP] 🔍 Searching App Store for: ${identifier}`);
195
+ const asResult = await appStoreService.fetchAppInfo(identifier);
196
+ if (asResult.found) {
197
+ appStoreInfo = toRegisteredAppStoreInfo({
198
+ bundleId: identifier,
199
+ appInfo: asResult,
200
+ });
201
+ appName = asResult.name || appName;
202
+ const localeInfo = asResult.supportedLocales && asResult.supportedLocales.length > 0
203
+ ? ` (${asResult.supportedLocales.length} locales)`
204
+ : "";
205
+ results.push(`🍎 App Store: ✅ Found (${asResult.name})${localeInfo}`);
206
+ }
207
+ else {
208
+ results.push(`🍎 App Store: ❌ Not found`);
209
+ }
210
+ }
211
+ // Check Google Play
212
+ if (store === "both" || store === "googlePlay") {
213
+ console.error(`[MCP] 🔍 Searching Google Play for: ${identifier}`);
214
+ const gpResult = await googlePlayService.fetchAppInfo(identifier);
215
+ if (gpResult.found) {
216
+ googlePlayInfo = toRegisteredGooglePlayInfo({
217
+ packageName: identifier,
218
+ appInfo: gpResult,
219
+ });
220
+ appName = gpResult.name || appName;
221
+ const localeInfo = gpResult.supportedLocales && gpResult.supportedLocales.length > 0
222
+ ? ` (${gpResult.supportedLocales.length} locales)`
223
+ : "";
224
+ results.push(`🤖 Google Play: ✅ Found (${gpResult.name})${localeInfo}`);
225
+ }
226
+ else {
227
+ results.push(`🤖 Google Play: ❌ Not found`);
228
+ }
229
+ }
230
+ // Must be found in at least one store
231
+ if (!appStoreInfo && !googlePlayInfo) {
232
+ return {
233
+ content: [
234
+ {
235
+ type: "text",
236
+ text: `❌ App not found.
237
+
238
+ **Search Results:**
239
+ ${results.map((r) => ` • ${r}`).join("\n")}
240
+
241
+ **Things to Check:**
242
+ • Verify identifier is correct: \`${identifier}\`
243
+ • Verify app is registered in the store
244
+ • Verify authentication settings are correct (use auth-check tool)`,
245
+ },
246
+ ],
247
+ };
248
+ }
249
+ // Register app
250
+ try {
251
+ console.error(`[MCP] 💾 Registering app with slug: ${slug}`);
252
+ const newApp = registerApp({
253
+ slug,
254
+ name: appName,
255
+ appStore: appStoreInfo,
256
+ googlePlay: googlePlayInfo,
257
+ });
258
+ console.error(`[MCP] ✅ App registered successfully`);
259
+ const storeIcons = [
260
+ appStoreInfo ? "🍎" : null,
261
+ googlePlayInfo ? "🤖" : null,
262
+ ]
263
+ .filter(Boolean)
264
+ .join("+");
265
+ const localeInfo = [];
266
+ if (appStoreInfo?.supportedLocales &&
267
+ appStoreInfo.supportedLocales.length > 0) {
268
+ localeInfo.push(`• App Store locales: ${appStoreInfo.supportedLocales.join(", ")}`);
269
+ }
270
+ if (googlePlayInfo?.supportedLocales &&
271
+ googlePlayInfo.supportedLocales.length > 0) {
272
+ localeInfo.push(`• Google Play locales: ${googlePlayInfo.supportedLocales.join(", ")}`);
273
+ }
274
+ return {
275
+ content: [
276
+ {
277
+ type: "text",
278
+ text: `✅ App registration complete (${storeIcons})
279
+
280
+ **Registration Info:**
281
+ • Slug: \`${newApp.slug}\`
282
+ • Name: ${newApp.name}
283
+ ${appStoreInfo ? `• App Store: ${appStoreInfo.bundleId} (ID: ${appStoreInfo.appId})` : ""}
284
+ ${googlePlayInfo ? `• Google Play: ${googlePlayInfo.packageName}` : ""}
285
+ ${localeInfo.length > 0 ? `\n**Supported Languages:**\n${localeInfo.map((l) => ` ${l}`).join("\n")}` : ""}
286
+
287
+ **Search Results:**
288
+ ${results.map((r) => ` • ${r}`).join("\n")}
289
+
290
+ You can now reference this app in other tools using the \`app: "${slug}"\` parameter.`,
291
+ },
292
+ ],
293
+ _meta: { app: newApp },
294
+ };
295
+ }
296
+ catch (error) {
297
+ const msg = error instanceof Error ? error.message : String(error);
298
+ return {
299
+ content: [
300
+ {
301
+ type: "text",
302
+ text: `❌ App registration failed: ${msg}`,
303
+ },
304
+ ],
305
+ };
306
+ }
307
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * setup-apps: Query apps from store and auto-register
3
+ */
4
+ import { type RegisteredApp } from "../../packages/configs/secrets-config/registered-apps.js";
5
+ interface SetupAppsOptions {
6
+ store?: "appStore" | "googlePlay" | "both";
7
+ packageName?: string;
8
+ }
9
+ export declare function handleSetupApps(options: SetupAppsOptions): Promise<{
10
+ content: {
11
+ type: "text";
12
+ text: string;
13
+ }[];
14
+ isError: boolean;
15
+ _meta?: undefined;
16
+ } | {
17
+ content: {
18
+ type: "text";
19
+ text: string;
20
+ }[];
21
+ isError?: undefined;
22
+ _meta?: undefined;
23
+ } | {
24
+ content: {
25
+ type: "text";
26
+ text: string;
27
+ }[];
28
+ _meta: {
29
+ registered: number;
30
+ skipped: number;
31
+ playStoreFound: number;
32
+ playStoreNotFound: number;
33
+ apps: {
34
+ id: string;
35
+ name: string;
36
+ bundleId: string;
37
+ sku: string;
38
+ isReleased: boolean;
39
+ }[];
40
+ app?: undefined;
41
+ };
42
+ isError?: undefined;
43
+ } | {
44
+ content: {
45
+ type: "text";
46
+ text: string;
47
+ }[];
48
+ _meta: {
49
+ app: RegisteredApp;
50
+ registered?: undefined;
51
+ skipped?: undefined;
52
+ playStoreFound?: undefined;
53
+ playStoreNotFound?: undefined;
54
+ apps?: undefined;
55
+ };
56
+ isError?: undefined;
57
+ }>;
58
+ export {};