@yoonion/mimi-seed-mcp 0.3.6 โ 0.3.8
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/dist/auth/playstore-auth.d.ts +4 -0
- package/dist/auth/playstore-auth.js +37 -0
- package/dist/auth/playstore-setup-cli.d.ts +2 -0
- package/dist/auth/playstore-setup-cli.js +68 -0
- package/dist/index.js +320 -190
- package/dist/playstore/tools.d.ts +18 -59
- package/dist/playstore/tools.js +0 -160
- package/package.json +4 -2
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { JWT } from 'google-auth-library';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
const SA_PATH = path.join(os.homedir(), '.mimi-seed', 'play-service-account.json');
|
|
6
|
+
export function getServiceAccountJson() {
|
|
7
|
+
if (!fs.existsSync(SA_PATH))
|
|
8
|
+
return null;
|
|
9
|
+
try {
|
|
10
|
+
return fs.readFileSync(SA_PATH, 'utf-8');
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function saveServiceAccountJson(json) {
|
|
17
|
+
const dir = path.dirname(SA_PATH);
|
|
18
|
+
if (!fs.existsSync(dir))
|
|
19
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
20
|
+
fs.writeFileSync(SA_PATH, json, { mode: 0o600 });
|
|
21
|
+
}
|
|
22
|
+
export function getServiceAccountClient() {
|
|
23
|
+
const json = getServiceAccountJson();
|
|
24
|
+
if (!json)
|
|
25
|
+
return null;
|
|
26
|
+
try {
|
|
27
|
+
const parsed = JSON.parse(json);
|
|
28
|
+
return new JWT({
|
|
29
|
+
email: parsed.client_email,
|
|
30
|
+
key: parsed.private_key,
|
|
31
|
+
scopes: ['https://www.googleapis.com/auth/androidpublisher'],
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { saveServiceAccountJson, getServiceAccountJson } from './playstore-auth.js';
|
|
3
|
+
import readline from 'node:readline';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
6
|
+
const ask = (q) => new Promise((r) => rl.question(q, r));
|
|
7
|
+
async function main() {
|
|
8
|
+
console.log('');
|
|
9
|
+
console.log(' ๐ค Mimi Seed โ Google Play ์๋น์ค ๊ณ์ ์ฐ๊ฒฐ');
|
|
10
|
+
console.log('');
|
|
11
|
+
const existing = getServiceAccountJson();
|
|
12
|
+
if (existing) {
|
|
13
|
+
try {
|
|
14
|
+
const parsed = JSON.parse(existing);
|
|
15
|
+
console.log(` โ
์ด๋ฏธ ์ฐ๊ฒฐ๋จ (${parsed.client_email ?? '?'})`);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
console.log(' โ ๏ธ ์ ์ฅ๋ ์๋น์ค ๊ณ์ ์ด ์์ง๋ง ํ์ฑ ์ค๋ฅ');
|
|
19
|
+
}
|
|
20
|
+
const answer = await ask(' ๋ค์ ์ค์ ํ ๋? (y/N): ');
|
|
21
|
+
if (answer.toLowerCase() !== 'y') {
|
|
22
|
+
rl.close();
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
console.log(' Google Play ์๋น์ค ๊ณ์ ํค JSON ํ์ผ์ด ํ์ํด:');
|
|
27
|
+
console.log(' 1. Google Cloud Console โ IAM & Admin โ Service Accounts');
|
|
28
|
+
console.log(' 2. ์๋น์ค ๊ณ์ ์ ํ โ Keys โ Add Key โ Create new key โ JSON');
|
|
29
|
+
console.log(' 3. ๋ค์ด๋ก๋ํ JSON ํ์ผ ๊ฒฝ๋ก๋ฅผ ์
๋ ฅํด');
|
|
30
|
+
console.log('');
|
|
31
|
+
const jsonPath = await ask(' ์๋น์ค ๊ณ์ JSON ํ์ผ ๊ฒฝ๋ก: ');
|
|
32
|
+
const trimmedPath = jsonPath.trim().replace(/^["']|["']$/g, '');
|
|
33
|
+
if (!fs.existsSync(trimmedPath)) {
|
|
34
|
+
console.log(` โ ํ์ผ ์์: ${trimmedPath}`);
|
|
35
|
+
rl.close();
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
const json = fs.readFileSync(trimmedPath, 'utf-8');
|
|
39
|
+
let parsed;
|
|
40
|
+
try {
|
|
41
|
+
parsed = JSON.parse(json);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
console.log(' โ JSON ํ์ฑ ์คํจ โ ์ฌ๋ฐ๋ฅธ ์๋น์ค ๊ณ์ ํค ํ์ผ์ธ์ง ํ์ธํด์ค');
|
|
45
|
+
rl.close();
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
if (parsed.type !== 'service_account' || !parsed.client_email || !parsed.private_key) {
|
|
49
|
+
console.log(' โ ์๋น์ค ๊ณ์ JSON ํ์์ด ์๋์ผ.');
|
|
50
|
+
console.log(' type="service_account", client_email, private_key ํ๋๊ฐ ์์ด์ผ ํด.');
|
|
51
|
+
rl.close();
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
saveServiceAccountJson(json);
|
|
55
|
+
console.log('');
|
|
56
|
+
console.log(` โ
์ ์ฅ ์๋ฃ! (${parsed.client_email})`);
|
|
57
|
+
console.log('');
|
|
58
|
+
console.log(' ์ด์ Claude Code์์:');
|
|
59
|
+
console.log(' "๋ด Play ์คํ ์ด ์ฑ ๋ฆฌ์คํ
๋ณด์ฌ์ค"');
|
|
60
|
+
console.log(' "Play ๊ตฌ๋
์ํ ๋ชฉ๋ก ๋ณด์ฌ์ค"');
|
|
61
|
+
console.log('');
|
|
62
|
+
console.log(' โ ๏ธ Play Console ๊ถํ ํ์ธ:');
|
|
63
|
+
console.log(' Play Console โ Users and permissions โ ์ด ์๋น์ค ๊ณ์ ์ถ๊ฐ');
|
|
64
|
+
console.log(' ์ฑ ๊ถํ์์ "View financial data" + "Manage store listing" ์ฒดํฌ');
|
|
65
|
+
console.log('');
|
|
66
|
+
rl.close();
|
|
67
|
+
}
|
|
68
|
+
main();
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,9 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { getAuthenticatedClient, getStoredTokens, startAuth } from './auth/google-auth.js';
|
|
6
|
+
import { getServiceAccountClient, getServiceAccountJson } from './auth/playstore-auth.js';
|
|
7
|
+
import { getAppStoreCredentials } from './appstore/auth.js';
|
|
8
|
+
import { createGoogleOneTimePurchase, createGoogleSubscription, updateGoogleProduct, deleteGoogleProduct, listGoogleProducts, createAppleOneTimePurchase, createAppleSubscription, updateAppleProduct, deleteAppleProduct, listAppleProducts, } from '@onesub/providers';
|
|
6
9
|
import { MIMI_SEED_CLIENT_ID, MIMI_SEED_CLIENT_SECRET } from './auth/constants.js';
|
|
7
10
|
import * as firebase from './firebase/tools.js';
|
|
8
11
|
import * as admob from './admob/tools.js';
|
|
@@ -35,6 +38,44 @@ function requireAuth() {
|
|
|
35
38
|
}
|
|
36
39
|
return client;
|
|
37
40
|
}
|
|
41
|
+
const PLAY_AUTH_HINT = [
|
|
42
|
+
'โ Google Play ์๋น์ค ๊ณ์ ์ด ์ฐ๊ฒฐ๋์ง ์์์ด.',
|
|
43
|
+
'',
|
|
44
|
+
'ํฐ๋ฏธ๋์์ ์ด๊ฒ๋ง ์คํํ๋ฉด ๋ผ:',
|
|
45
|
+
'',
|
|
46
|
+
' npx -y @yoonion/mimi-seed-mcp mimi-seed-playstore-auth',
|
|
47
|
+
'',
|
|
48
|
+
'์๋น์ค ๊ณ์ JSON ํ์ผ ๊ฒฝ๋ก๋ฅผ ์
๋ ฅํ๋ฉด ์ ์ฅ ์๋ฃ.',
|
|
49
|
+
'๊ทธ ๋ค์์ ๋ค์ ๋ฌผ์ด๋ด์ค.',
|
|
50
|
+
].join('\n');
|
|
51
|
+
const APPSTORE_AUTH_HINT = [
|
|
52
|
+
'โ App Store Connect ์ธ์ฆ์ด ์ค์ ๋์ง ์์์ด.',
|
|
53
|
+
'',
|
|
54
|
+
'ํฐ๋ฏธ๋์์ ์ด๊ฒ๋ง ์คํํ๋ฉด ๋ผ:',
|
|
55
|
+
'',
|
|
56
|
+
' npx -y @yoonion/mimi-seed-mcp mimi-seed-appstore-auth',
|
|
57
|
+
'',
|
|
58
|
+
'Issuer ID, Key ID, .p8 ํ์ผ ๊ฒฝ๋ก๋ฅผ ์
๋ ฅํ๋ฉด ์ ์ฅ ์๋ฃ.',
|
|
59
|
+
'๊ทธ ๋ค์์ ๋ค์ ๋ฌผ์ด๋ด์ค.',
|
|
60
|
+
].join('\n');
|
|
61
|
+
function requirePlayStoreAuth() {
|
|
62
|
+
const client = getServiceAccountClient();
|
|
63
|
+
if (!client)
|
|
64
|
+
throw new Error(PLAY_AUTH_HINT);
|
|
65
|
+
return client;
|
|
66
|
+
}
|
|
67
|
+
function requireServiceAccountJson() {
|
|
68
|
+
const json = getServiceAccountJson();
|
|
69
|
+
if (!json)
|
|
70
|
+
throw new Error(PLAY_AUTH_HINT);
|
|
71
|
+
return json;
|
|
72
|
+
}
|
|
73
|
+
function requireAppStoreCreds() {
|
|
74
|
+
const creds = getAppStoreCredentials();
|
|
75
|
+
if (!creds)
|
|
76
|
+
throw new Error(APPSTORE_AUTH_HINT);
|
|
77
|
+
return creds;
|
|
78
|
+
}
|
|
38
79
|
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
39
80
|
// Firebase Tools
|
|
40
81
|
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
@@ -258,7 +299,7 @@ server.tool('admob_create_ad_unit', 'AdMob ๊ด๊ณ ๋จ์ ์์ฑ (v1beta โ Limi
|
|
|
258
299
|
// Google Play Store Tools
|
|
259
300
|
// โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
260
301
|
server.tool('playstore_get_app', 'Google Play ์ฑ ์์ธ ์ ๋ณด ์กฐํ', { packageName: z.string().describe('ํจํค์ง๋ช
(์: com.findthem.app)') }, async ({ packageName }) => {
|
|
261
|
-
const auth =
|
|
302
|
+
const auth = requirePlayStoreAuth();
|
|
262
303
|
const details = await playstore.getAppDetails(auth, packageName);
|
|
263
304
|
return { content: [{ type: 'text', text: JSON.stringify(details, null, 2) }] };
|
|
264
305
|
});
|
|
@@ -266,7 +307,7 @@ server.tool('playstore_get_listing', 'Google Play ์คํ ์ด ๋ฆฌ์คํ
์กฐํ (
|
|
|
266
307
|
packageName: z.string().describe('ํจํค์ง๋ช
'),
|
|
267
308
|
language: z.string().default('ko-KR').describe('์ธ์ด ์ฝ๋ (๊ธฐ๋ณธ: ko-KR)'),
|
|
268
309
|
}, async ({ packageName, language }) => {
|
|
269
|
-
const auth =
|
|
310
|
+
const auth = requirePlayStoreAuth();
|
|
270
311
|
const listing = await playstore.getListing(auth, packageName, language);
|
|
271
312
|
return { content: [{ type: 'text', text: JSON.stringify(listing, null, 2) }] };
|
|
272
313
|
});
|
|
@@ -277,14 +318,14 @@ server.tool('playstore_update_listing', 'Google Play ์คํ ์ด ๋ฆฌ์คํ
์์
|
|
|
277
318
|
shortDescription: z.string().optional().describe('์งง์ ์ค๋ช
(80์ ์ด๋ด)'),
|
|
278
319
|
fullDescription: z.string().optional().describe('์ ์ฒด ์ค๋ช
(4000์ ์ด๋ด)'),
|
|
279
320
|
}, async ({ packageName, language, title, shortDescription, fullDescription }) => {
|
|
280
|
-
const auth =
|
|
321
|
+
const auth = requirePlayStoreAuth();
|
|
281
322
|
const result = await playstore.updateListing(auth, packageName, language, {
|
|
282
323
|
title, shortDescription, fullDescription,
|
|
283
324
|
});
|
|
284
325
|
return { content: [{ type: 'text', text: `์์ ์๋ฃ:\n${JSON.stringify(result, null, 2)}` }] };
|
|
285
326
|
});
|
|
286
327
|
server.tool('playstore_list_tracks', 'Google Play ๋ฆด๋ฆฌ์ค ํธ๋ ํํฉ (ํ๋ก๋์
/๋ฒ ํ/์ํ/๋ด๋ถ)', { packageName: z.string().describe('ํจํค์ง๋ช
') }, async ({ packageName }) => {
|
|
287
|
-
const auth =
|
|
328
|
+
const auth = requirePlayStoreAuth();
|
|
288
329
|
const tracks = await playstore.listTracks(auth, packageName);
|
|
289
330
|
return { content: [{ type: 'text', text: JSON.stringify(tracks, null, 2) }] };
|
|
290
331
|
});
|
|
@@ -293,7 +334,7 @@ server.tool('playstore_list_images', 'Google Play ๋ฆฌ์คํ
์ด๋ฏธ์ง ๋ชฉ๋ก ์กฐ
|
|
|
293
334
|
language: z.string().describe('์ธ์ด ์ฝ๋ (์: ko-KR)'),
|
|
294
335
|
imageType: z.enum(['featureGraphic', 'icon', 'phoneScreenshots', 'promoGraphic', 'sevenInchScreenshots', 'tenInchScreenshots', 'tvBanner', 'tvScreenshots', 'wearScreenshots']).describe('์ด๋ฏธ์ง ํ์
'),
|
|
295
336
|
}, async ({ packageName, language, imageType }) => {
|
|
296
|
-
const auth =
|
|
337
|
+
const auth = requirePlayStoreAuth();
|
|
297
338
|
const images = await playstore.listImages(auth, packageName, language, imageType);
|
|
298
339
|
return { content: [{ type: 'text', text: JSON.stringify(images, null, 2) }] };
|
|
299
340
|
});
|
|
@@ -303,7 +344,7 @@ server.tool('playstore_upload_image', 'Google Play ๋ฆฌ์คํ
์ด๋ฏธ์ง ๋จ์ผ
|
|
|
303
344
|
imageType: z.enum(['featureGraphic', 'icon', 'phoneScreenshots', 'promoGraphic', 'sevenInchScreenshots', 'tenInchScreenshots', 'tvBanner', 'tvScreenshots', 'wearScreenshots']),
|
|
304
345
|
filePath: z.string().describe('์
๋ก๋ํ ์ด๋ฏธ์ง ์ ๋ ๊ฒฝ๋ก'),
|
|
305
346
|
}, async ({ packageName, language, imageType, filePath }) => {
|
|
306
|
-
const auth =
|
|
347
|
+
const auth = requirePlayStoreAuth();
|
|
307
348
|
const result = await playstore.uploadImage(auth, packageName, language, imageType, filePath);
|
|
308
349
|
return { content: [{ type: 'text', text: `โ
์
๋ก๋ ์๋ฃ\n${JSON.stringify(result, null, 2)}` }] };
|
|
309
350
|
});
|
|
@@ -312,7 +353,7 @@ server.tool('playstore_delete_all_images', 'Google Play ๋ฆฌ์คํ
ํน์ imageTy
|
|
|
312
353
|
language: z.string().describe('์ธ์ด ์ฝ๋'),
|
|
313
354
|
imageType: z.enum(['featureGraphic', 'icon', 'phoneScreenshots', 'promoGraphic', 'sevenInchScreenshots', 'tenInchScreenshots', 'tvBanner', 'tvScreenshots', 'wearScreenshots']),
|
|
314
355
|
}, async ({ packageName, language, imageType }) => {
|
|
315
|
-
const auth =
|
|
356
|
+
const auth = requirePlayStoreAuth();
|
|
316
357
|
const result = await playstore.deleteAllImages(auth, packageName, language, imageType);
|
|
317
358
|
return { content: [{ type: 'text', text: `โ
์ ์ฒด ์ญ์ \n${JSON.stringify(result, null, 2)}` }] };
|
|
318
359
|
});
|
|
@@ -322,7 +363,7 @@ server.tool('playstore_replace_images', 'Google Play ๋ฆฌ์คํ
์ด๋ฏธ์ง ์ผ๊ด
|
|
|
322
363
|
imageType: z.enum(['featureGraphic', 'icon', 'phoneScreenshots', 'promoGraphic', 'sevenInchScreenshots', 'tenInchScreenshots', 'tvBanner', 'tvScreenshots', 'wearScreenshots']),
|
|
323
364
|
filePaths: z.array(z.string()).describe('์
๋ก๋ํ ์ด๋ฏธ์ง ์ ๋ ๊ฒฝ๋ก ๋ฐฐ์ด (์์ = ๋
ธ์ถ ์์)'),
|
|
324
365
|
}, async ({ packageName, language, imageType, filePaths }) => {
|
|
325
|
-
const auth =
|
|
366
|
+
const auth = requirePlayStoreAuth();
|
|
326
367
|
const result = await playstore.replaceImages(auth, packageName, language, imageType, filePaths);
|
|
327
368
|
return { content: [{ type: 'text', text: `โ
${result.count}์ฅ ๊ต์ฒด ์๋ฃ\n${JSON.stringify(result, null, 2)}` }] };
|
|
328
369
|
});
|
|
@@ -333,7 +374,7 @@ server.tool('playstore_update_release_notes', "Google Play ํธ๋ ๋ฆด๋ฆฌ์ค์ '
|
|
|
333
374
|
language: z.string().describe('์ธ์ด ์ฝ๋ (์: ko-KR, en-US)'),
|
|
334
375
|
text: z.string().describe('๋ฆด๋ฆฌ์ค ๋
ธํธ ๋ณธ๋ฌธ (500์ ์ด๋ด)'),
|
|
335
376
|
}, async ({ packageName, track, versionCode, language, text }) => {
|
|
336
|
-
const auth =
|
|
377
|
+
const auth = requirePlayStoreAuth();
|
|
337
378
|
const result = await playstore.updateReleaseNotes(auth, packageName, track, versionCode, language, text);
|
|
338
379
|
return { content: [{ type: 'text', text: `โ
${packageName} ${track} v${versionCode} ${language} ๋
ธํธ ๋ฐ์\n\n${JSON.stringify(result, null, 2)}` }] };
|
|
339
380
|
});
|
|
@@ -343,12 +384,12 @@ server.tool('playstore_update_latest_release_notes', "Google Play ํธ๋์ ์ต
|
|
|
343
384
|
language: z.string().describe('์ธ์ด ์ฝ๋ (์: ko-KR)'),
|
|
344
385
|
text: z.string().describe('๋ฆด๋ฆฌ์ค ๋
ธํธ ๋ณธ๋ฌธ (500์ ์ด๋ด)'),
|
|
345
386
|
}, async ({ packageName, track, language, text }) => {
|
|
346
|
-
const auth =
|
|
387
|
+
const auth = requirePlayStoreAuth();
|
|
347
388
|
const result = await playstore.updateLatestReleaseNotes(auth, packageName, track, language, text);
|
|
348
389
|
return { content: [{ type: 'text', text: `โ
${packageName} ${track} (versionCodes=${JSON.stringify(result.updatedVersionCodes)}) ${language} ๋
ธํธ ๋ฐ์\n\n${JSON.stringify(result, null, 2)}` }] };
|
|
349
390
|
});
|
|
350
391
|
server.tool('playstore_list_reviews', 'Google Play ๋ฆฌ๋ทฐ ๋ชฉ๋ก ์กฐํ', { packageName: z.string().describe('ํจํค์ง๋ช
') }, async ({ packageName }) => {
|
|
351
|
-
const auth =
|
|
392
|
+
const auth = requirePlayStoreAuth();
|
|
352
393
|
const reviews = await playstore.listReviews(auth, packageName);
|
|
353
394
|
return { content: [{ type: 'text', text: JSON.stringify(reviews, null, 2) }] };
|
|
354
395
|
});
|
|
@@ -357,124 +398,121 @@ server.tool('playstore_reply_review', 'Google Play ๋ฆฌ๋ทฐ์ ๋ต๋ณ', {
|
|
|
357
398
|
reviewId: z.string().describe('๋ฆฌ๋ทฐ ID'),
|
|
358
399
|
replyText: z.string().describe('๋ต๋ณ ๋ด์ฉ'),
|
|
359
400
|
}, async ({ packageName, reviewId, replyText }) => {
|
|
360
|
-
const auth =
|
|
401
|
+
const auth = requirePlayStoreAuth();
|
|
361
402
|
const result = await playstore.replyToReview(auth, packageName, reviewId, replyText);
|
|
362
403
|
return { content: [{ type: 'text', text: `๋ต๋ณ ์๋ฃ:\n${JSON.stringify(result, null, 2)}` }] };
|
|
363
404
|
});
|
|
364
405
|
server.tool('playstore_list_inapp_products', 'Google Play ์ธ์ฑ ์ํ ๋ชฉ๋ก', { packageName: z.string().describe('ํจํค์ง๋ช
') }, async ({ packageName }) => {
|
|
365
|
-
const auth =
|
|
406
|
+
const auth = requirePlayStoreAuth();
|
|
366
407
|
const products = await playstore.listInAppProducts(auth, packageName);
|
|
367
408
|
return { content: [{ type: 'text', text: JSON.stringify(products, null, 2) }] };
|
|
368
409
|
});
|
|
369
410
|
server.tool('playstore_list_subscriptions', 'Google Play ๊ตฌ๋
์ํ ๋ชฉ๋ก', { packageName: z.string().describe('ํจํค์ง๋ช
') }, async ({ packageName }) => {
|
|
370
|
-
const auth =
|
|
411
|
+
const auth = requirePlayStoreAuth();
|
|
371
412
|
const subs = await playstore.listSubscriptions(auth, packageName);
|
|
372
413
|
return { content: [{ type: 'text', text: JSON.stringify(subs, null, 2) }] };
|
|
373
414
|
});
|
|
374
415
|
server.tool('playstore_create_onetime_product', [
|
|
375
|
-
'Google Play์ ์ผํ์ฑ ์ธ์ฑ
|
|
376
|
-
'
|
|
377
|
-
'Play Console ๊ถํ: "Manage store presence" ํ์. ํ์ฑํ๋ Console์์ ๋ณ๋ ํ ๊ธ.',
|
|
416
|
+
'Google Play์ ์ผํ์ฑ ์ธ์ฑ ์ํ(์๋น์ฑ ๋๋ ๋น์๋น์ฑ)์ ์์ฑ.',
|
|
417
|
+
'Play Console ๊ถํ: "Manage store presence" ํ์. ์์ฑ ํ Console์์ ํ์ฑํ ํ์.',
|
|
378
418
|
].join(' '), {
|
|
379
419
|
packageName: z.string().describe('ํจํค์ง๋ช
(์: com.example.app)'),
|
|
380
420
|
productId: z
|
|
381
421
|
.string()
|
|
382
422
|
.describe('์ํ ID (์๋ฌธ์/์ซ์/์ธ๋์ค์ฝ์ด/์ , ์: premium_unlock). ํ ๋ฒ ์ ํ๋ฉด ๋ณ๊ฒฝ ๋ถ๊ฐ.'),
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
.
|
|
390
|
-
|
|
391
|
-
.
|
|
392
|
-
|
|
393
|
-
.
|
|
394
|
-
|
|
395
|
-
eurPrice: z.number().describe('Play๊ฐ ์ ๊ท ์ง์ญ launch ์ ์ฌ์ฉํ EUR ๊ฐ๊ฒฉ'),
|
|
396
|
-
})
|
|
423
|
+
name: z.string().describe('์ํ ์ด๋ฆ (์คํ ์ด ๋
ธ์ถ ์ ๋ชฉ)'),
|
|
424
|
+
price: z.number().int().describe('์ฃผ ํตํ ๊ธฐ์ค ๊ฐ๊ฒฉ (์ต์ ๋จ์: USD/EUR์ด๋ฉด cents, KRW/JPY์ด๋ฉด ์ํ ์ ์. ์: USD $4.99 โ 499, KRW โฉ5,900 โ 5900)'),
|
|
425
|
+
currency: z.string().default('USD').describe('ISO 4217 ํตํ ์ฝ๋ (๊ธฐ๋ณธ USD)'),
|
|
426
|
+
type: z
|
|
427
|
+
.enum(['consumable', 'non_consumable'])
|
|
428
|
+
.default('non_consumable')
|
|
429
|
+
.describe('์ํ ์ ํ (์๋น์ฑ/๋น์๋น์ฑ). ์ฑ์ด consumePurchase ํธ์ถํ๋ฉด ์๋น์ฑ.'),
|
|
430
|
+
extraRegions: z
|
|
431
|
+
.array(z.object({
|
|
432
|
+
currency: z.string().describe('ISO 4217 ํตํ ์ฝ๋ (์: KRW, JPY, GBP)'),
|
|
433
|
+
price: z.number().describe('๊ฐ๊ฒฉ (์ต์ ๋จ์: KRW โฉ1,100 โ 1100, USD $0.99 โ 99)'),
|
|
434
|
+
}))
|
|
397
435
|
.optional()
|
|
398
|
-
.describe('
|
|
436
|
+
.describe('์ถ๊ฐ ์ง์ญ๋ณ ๋ช
์ ๊ฐ๊ฒฉ. ์๋ ํ์ฐ์ด ๋ถ์ ํํ KRW/JPY ๋ฑ์ ์ง์ ์ง์ .'),
|
|
399
437
|
}, async (args) => {
|
|
400
|
-
const
|
|
401
|
-
const result = await
|
|
438
|
+
const json = requireServiceAccountJson();
|
|
439
|
+
const result = await createGoogleOneTimePurchase({
|
|
440
|
+
packageName: args.packageName,
|
|
441
|
+
productId: args.productId,
|
|
442
|
+
name: args.name,
|
|
443
|
+
price: args.price,
|
|
444
|
+
currency: args.currency,
|
|
445
|
+
type: args.type,
|
|
446
|
+
...(args.extraRegions && { extraRegions: args.extraRegions }),
|
|
447
|
+
serviceAccountKey: json,
|
|
448
|
+
});
|
|
449
|
+
if (!result.success) {
|
|
450
|
+
return { content: [{ type: 'text', text: `โ ์ํ ์์ฑ ์คํจ: ${result.error}` }] };
|
|
451
|
+
}
|
|
402
452
|
return {
|
|
403
|
-
content: [
|
|
404
|
-
{
|
|
453
|
+
content: [{
|
|
405
454
|
type: 'text',
|
|
406
455
|
text: [
|
|
407
|
-
`โ Play ์ผํ์ฑ ์ํ
|
|
408
|
-
`productId: ${
|
|
409
|
-
`price:
|
|
410
|
-
args.newRegionsPricing
|
|
411
|
-
? `์ ๊ท ์ง์ญ: $${args.newRegionsPricing.usdPrice} / โฌ${args.newRegionsPricing.eurPrice}`
|
|
412
|
-
: '์ ๊ท ์ง์ญ: OFF (newRegionsPricing ๋ฏธ์ง์ )',
|
|
413
|
-
'โ ๊ธฐ์กด์ ๋ค๊ตญ์ด/๋ค์ง์ญ ๋ฑ๋ก๋ ์ํ์ด๋ฉด listingsยทpurchaseOptions๊ฐ ํต์งธ ๊ต์ฒด๋จ.',
|
|
456
|
+
`โ Play ์ผํ์ฑ ์ํ ์์ฑ ์๋ฃ`,
|
|
457
|
+
`productId: ${result.productId}`,
|
|
458
|
+
`price: ${args.price} ${args.currency}`,
|
|
414
459
|
'',
|
|
415
460
|
'Play Console์์ ํ์ฑํ ํ์ธ:',
|
|
416
461
|
`https://play.google.com/console/u/0/developers/-/app/-/managed-products?package=${encodeURIComponent(args.packageName)}`,
|
|
417
|
-
'',
|
|
418
|
-
'์๋ต:',
|
|
419
|
-
JSON.stringify(result, null, 2),
|
|
420
462
|
].join('\n'),
|
|
421
|
-
},
|
|
422
|
-
],
|
|
463
|
+
}],
|
|
423
464
|
};
|
|
424
465
|
});
|
|
425
466
|
server.tool('playstore_create_subscription', [
|
|
426
467
|
'Google Play์ ์๋ ๊ฐฑ์ ๊ตฌ๋
์ ์์ฑํ๊ณ baseplan์ ํ์ฑํ.',
|
|
427
|
-
'๊ตฌ๋
|
|
428
|
-
'์ด๋ฏธ ๊ฐ์ productId๊ฐ ์์ผ๋ฉด
|
|
468
|
+
'๊ตฌ๋
์์ฑ โ baseplan(๊ฐ๊ฒฉยท์ฃผ๊ธฐ) ์ถ๊ฐ โ ์๋ ํ์ฑํ.',
|
|
469
|
+
'์ด๋ฏธ ๊ฐ์ productId๊ฐ ์์ผ๋ฉด ์์ฑ ์คํจ (Play API ํน์ฑ์ upsert ๋ฏธ์ง์).',
|
|
429
470
|
].join(' '), {
|
|
430
471
|
packageName: z.string().describe('ํจํค์ง๋ช
'),
|
|
431
472
|
productId: z
|
|
432
473
|
.string()
|
|
433
|
-
.describe('๊ตฌ๋
์ํ ID (์๋ฌธ์/์ซ์/์ธ๋์ค์ฝ์ด/์ ,
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
.
|
|
440
|
-
|
|
441
|
-
.
|
|
442
|
-
|
|
443
|
-
.
|
|
444
|
-
|
|
445
|
-
priceUsd: z.number().describe('USD ๊ฐ๊ฒฉ'),
|
|
446
|
-
gracePeriod: z
|
|
447
|
-
.enum(['P0D', 'P3D', 'P7D', 'P14D', 'P30D'])
|
|
474
|
+
.describe('๊ตฌ๋
์ํ ID (์๋ฌธ์/์ซ์/์ธ๋์ค์ฝ์ด/์ , ์: premium_monthly)'),
|
|
475
|
+
name: z.string().describe('๊ตฌ๋
์ ๋ชฉ (์คํ ์ด ๋
ธ์ถ)'),
|
|
476
|
+
price: z.number().int().describe('์ฃผ ํตํ ๊ธฐ์ค ๊ฐ๊ฒฉ (์ต์ ๋จ์: USD cents. ์: $4.99 โ 499, โฉ5,900 โ 5900)'),
|
|
477
|
+
currency: z.string().default('USD').describe('ISO 4217 ํตํ ์ฝ๋ (๊ธฐ๋ณธ USD)'),
|
|
478
|
+
period: z
|
|
479
|
+
.enum(['monthly', 'yearly'])
|
|
480
|
+
.describe('์ฒญ๊ตฌ ์ฃผ๊ธฐ'),
|
|
481
|
+
extraRegions: z
|
|
482
|
+
.array(z.object({
|
|
483
|
+
currency: z.string().describe('ISO 4217 ํตํ ์ฝ๋ (์: KRW, JPY)'),
|
|
484
|
+
price: z.number().describe('๊ฐ๊ฒฉ (์ต์ ๋จ์)'),
|
|
485
|
+
}))
|
|
448
486
|
.optional()
|
|
449
|
-
.describe('
|
|
450
|
-
autoActivate: z
|
|
451
|
-
.boolean()
|
|
452
|
-
.optional()
|
|
453
|
-
.describe('์์ฑ ํ baseplan ์๋ ํ์ฑํ (๊ธฐ๋ณธ true). false๋ฉด Console์์ ์๋ ํ์ฑํ.'),
|
|
454
|
-
newRegionsPricing: z
|
|
455
|
-
.object({
|
|
456
|
-
usdPrice: z.number(),
|
|
457
|
-
eurPrice: z.number(),
|
|
458
|
-
})
|
|
459
|
-
.optional()
|
|
460
|
-
.describe('์ ๊ท ์ถ์ ์ง์ญ ์๋ ๊ฐ๊ฒฉ (์ ํ). ๋ฏธ์ง์ ์ ์ ๊ท ์ง์ญ์ ๋
ธ์ถ ์ ๋จ.'),
|
|
487
|
+
.describe('์ถ๊ฐ ์ง์ญ๋ณ ๋ช
์ ๊ฐ๊ฒฉ'),
|
|
461
488
|
}, async (args) => {
|
|
462
|
-
const
|
|
463
|
-
const result = await
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
489
|
+
const json = requireServiceAccountJson();
|
|
490
|
+
const result = await createGoogleSubscription({
|
|
491
|
+
packageName: args.packageName,
|
|
492
|
+
productId: args.productId,
|
|
493
|
+
name: args.name,
|
|
494
|
+
price: args.price,
|
|
495
|
+
currency: args.currency,
|
|
496
|
+
period: args.period,
|
|
497
|
+
...(args.extraRegions && { extraRegions: args.extraRegions }),
|
|
498
|
+
serviceAccountKey: json,
|
|
499
|
+
});
|
|
500
|
+
if (!result.success) {
|
|
501
|
+
return { content: [{ type: 'text', text: `โ ๊ตฌ๋
์์ฑ ์คํจ: ${result.error}` }] };
|
|
502
|
+
}
|
|
503
|
+
return {
|
|
504
|
+
content: [{
|
|
505
|
+
type: 'text',
|
|
506
|
+
text: [
|
|
507
|
+
`โ Play ๊ตฌ๋
์์ฑ ์๋ฃ`,
|
|
508
|
+
`productId: ${result.productId}`,
|
|
509
|
+
`price: ${args.price} ${args.currency} / ${args.period}`,
|
|
510
|
+
'',
|
|
511
|
+
'Play Console:',
|
|
512
|
+
`https://play.google.com/console/u/0/developers/-/app/-/subscriptions?package=${encodeURIComponent(args.packageName)}`,
|
|
513
|
+
].join('\n'),
|
|
514
|
+
}],
|
|
515
|
+
};
|
|
478
516
|
});
|
|
479
517
|
server.tool('playstore_verify_service_account', [
|
|
480
518
|
"์๋น์ค ๊ณ์ JSON์ด ์ฃผ์ด์ง packageName์ ๋ํด Play Developer API ํธ์ถ ๊ฐ๋ฅํ์ง + 'View financial data' ๊ถํ๊น์ง ์๋์ง ๊ฒ์ฆ.",
|
|
@@ -795,116 +833,208 @@ server.tool('appstore_reply_review', [
|
|
|
795
833
|
});
|
|
796
834
|
// --- App Store IAP / ๊ตฌ๋
์์ฑ ---
|
|
797
835
|
server.tool('appstore_create_inapp_purchase', [
|
|
798
|
-
'App Store์ ์ผํ์ฑ ์ธ์ฑ ๊ตฌ๋งค(IAP)๋ฅผ ์์ฑ โ
|
|
799
|
-
'
|
|
800
|
-
'autoSubmit์ด ์คํจํด๋ draft + ๋ก์ปฌ๋ผ์ด์ ์ด์
+ ๊ฐ๊ฒฉ์ ์ ์ง๋จ. ์ด๋๊น์ง ์งํ๋๋์ง ์๋ต์ ํ์.',
|
|
801
|
-
'์ ์ถ์ด ๋งํ๋ ํํ ์ด์ : ๋ฆฌ๋ทฐ ๋
ธํธ ๋ถ์กฑ / ์คํฌ๋ฆฐ์ท ๋ฏธ์ฒจ๋ถ / ๋ถ๋ชจ ์ฑ ๋ฉํ๋ฐ์ดํฐ ๋ฏธ์ โ ๊ทธ๋ ์ฝ์ ๋งํฌ๋ก ์ด๋ํด ๋ง๋ฌด๋ฆฌ.',
|
|
836
|
+
'App Store์ ์ผํ์ฑ ์ธ์ฑ ๊ตฌ๋งค(IAP)๋ฅผ ์์ฑ โ CONSUMABLE (์๋น์ฑ) / NON_CONSUMABLE (๋น์๋น์ฑ).',
|
|
837
|
+
'์์ฑ ํ App Store Connect์์ ์คํฌ๋ฆฐ์ทยท๋ฆฌ๋ทฐ ๋
ธํธ๋ฅผ ์ถ๊ฐํด์ผ ์ฌ์ฌ ์ ์ถ ๊ฐ๋ฅ.',
|
|
802
838
|
].join(' '), {
|
|
803
839
|
appId: z.string().describe('App Store ์ฑ ID (appstore_list_apps ๊ฒฐ๊ณผ์ id, ์ซ์ํ)'),
|
|
804
840
|
productId: z
|
|
805
841
|
.string()
|
|
806
842
|
.describe('์ํ ID (๊ธ๋ก๋ฒ unique ๊ถ์ฅ: ์ com.example.coins_100)'),
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
.string()
|
|
843
|
+
name: z.string().describe('์ํ ์ด๋ฆ (์คํ ์ด ๋
ธ์ถ, ์ต๋ 30์)'),
|
|
844
|
+
price: z.number().int().describe('๊ฐ๊ฒฉ (์ต์ ๋จ์: USD cents. ์: $0.99 โ 99, โฉ1,100 โ 1100)'),
|
|
845
|
+
currency: z.string().default('USD').describe('ISO 4217 ํตํ ์ฝ๋ (๊ธฐ๋ณธ USD)'),
|
|
846
|
+
type: z
|
|
847
|
+
.enum(['consumable', 'non_consumable'])
|
|
848
|
+
.default('non_consumable')
|
|
849
|
+
.describe('IAP ์ ํ (์๋น์ฑ/๋น์๋น์ฑ)'),
|
|
850
|
+
extraRegions: z
|
|
851
|
+
.array(z.object({
|
|
852
|
+
currency: z.string().describe('ISO 4217 ํตํ ์ฝ๋ (์: KRW)'),
|
|
853
|
+
price: z.number().describe('๊ฐ๊ฒฉ (์ต์ ๋จ์)'),
|
|
854
|
+
}))
|
|
817
855
|
.optional()
|
|
818
|
-
.describe('
|
|
819
|
-
|
|
820
|
-
familySharable: z.boolean().optional().describe('ํจ๋ฐ๋ฆฌ ๊ณต์ ๊ฐ๋ฅ (๊ธฐ๋ณธ false)'),
|
|
821
|
-
autoSubmit: z
|
|
822
|
-
.boolean()
|
|
823
|
-
.optional()
|
|
824
|
-
.describe('์์ฑ ํ ์๋ ์ฌ์ฌ ์ ์ถ ์๋ (๊ธฐ๋ณธ true). ์คํจํด๋ draft๋ ์ ์ง.'),
|
|
856
|
+
.describe('์ถ๊ฐ ์ง์ญ๋ณ ๋ช
์ ๊ฐ๊ฒฉ'),
|
|
857
|
+
bundleId: z.string().optional().describe('๋ฒ๋ค ID (appId ๋์ ์ฌ์ฉ ๊ฐ๋ฅ)'),
|
|
825
858
|
}, async (args) => {
|
|
826
|
-
const
|
|
827
|
-
const
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
859
|
+
const creds = requireAppStoreCreds();
|
|
860
|
+
const result = await createAppleOneTimePurchase({
|
|
861
|
+
appId: args.appId,
|
|
862
|
+
bundleId: args.bundleId,
|
|
863
|
+
productId: args.productId,
|
|
864
|
+
name: args.name,
|
|
865
|
+
price: args.price,
|
|
866
|
+
currency: args.currency,
|
|
867
|
+
type: args.type,
|
|
868
|
+
...(args.extraRegions && { extraRegions: args.extraRegions }),
|
|
869
|
+
keyId: creds.keyId,
|
|
870
|
+
issuerId: creds.issuerId,
|
|
871
|
+
privateKey: creds.privateKey,
|
|
872
|
+
});
|
|
873
|
+
if (!result.success) {
|
|
874
|
+
const hint = result.errorType === 'DUPLICATE'
|
|
875
|
+
? '\n์ด๋ฏธ ๊ฐ์ productId๊ฐ ์กด์ฌํด. App Store Connect์์ ํ์ธํด์ค.'
|
|
876
|
+
: result.errorType === 'PRICE_NOT_FOUND'
|
|
877
|
+
? `\n๊ฐ์ฅ ๊ฐ๊น์ด ๊ฐ๊ฒฉ: ${JSON.stringify(result.priceNearest)}`
|
|
878
|
+
: '';
|
|
879
|
+
return { content: [{ type: 'text', text: `โ IAP ์์ฑ ์คํจ: ${result.error}${hint}` }] };
|
|
880
|
+
}
|
|
881
|
+
return {
|
|
882
|
+
content: [{
|
|
883
|
+
type: 'text',
|
|
884
|
+
text: [
|
|
885
|
+
`โ App Store IAP ์์ฑ ์๋ฃ`,
|
|
886
|
+
`productId: ${result.productId}`,
|
|
887
|
+
`internalId: ${result.internalId}`,
|
|
888
|
+
result.priceSet ? `โ ๊ฐ๊ฒฉ ์ค์ ๋จ` : `โ ๊ฐ๊ฒฉ ๋ฏธ์ค์ (๊ฐ์ฅ ๊ฐ๊น์ด ๊ฐ๊ฒฉ: ${JSON.stringify(result.priceNearest)})`,
|
|
889
|
+
result.extraRegionsSet?.length ? `โ ์ถ๊ฐ ์ง์ญ: ${result.extraRegionsSet.join(', ')}` : '',
|
|
890
|
+
'',
|
|
891
|
+
'์คํฌ๋ฆฐ์ทยท๋ฆฌ๋ทฐ ๋
ธํธ๋ฅผ ์ถ๊ฐํ ํ App Store Connect์์ ์ฌ์ฌ ์ ์ถ:',
|
|
892
|
+
`https://appstoreconnect.apple.com/apps/${args.appId}/distribution/iaps`,
|
|
893
|
+
].filter(Boolean).join('\n'),
|
|
894
|
+
}],
|
|
895
|
+
};
|
|
852
896
|
});
|
|
853
897
|
server.tool('appstore_create_subscription', [
|
|
854
|
-
'App Store์ ์๋ ๊ฐฑ์ ๊ตฌ๋
์ ์์ฑ โ Subscription Group
|
|
855
|
-
'
|
|
856
|
-
'groupReferenceName์ด ๊ฐ์ ๊ทธ๋ฃน ๋ด ๊ตฌ๋
์ ์ฌ์ฉ์๊ฐ ํ ๋ฒ์ ํ๋๋ง ๊ฐ์ง ์ ์์ (upgrade/downgrade ๊ฐ๋ฅ).',
|
|
857
|
-
'autoSubmit ์คํจ ์์๋ draft + ๊ฐ๊ฒฉ๊น์ง๋ ์ ์ง โ ์ด๋๊น์ง ๋๋์ง ์๋ต์ผ๋ก ์ ์ ์์.',
|
|
898
|
+
'App Store์ ์๋ ๊ฐฑ์ ๊ตฌ๋
์ ์์ฑ โ Subscription Group ์๋ ์์ฑ ํฌํจ.',
|
|
899
|
+
'์์ฑ ํ App Store Connect์์ ์คํฌ๋ฆฐ์ทยท๋ฆฌ๋ทฐ ๋
ธํธ๋ฅผ ์ถ๊ฐํด์ผ ์ฌ์ฌ ์ ์ถ ๊ฐ๋ฅ.',
|
|
858
900
|
].join(' '), {
|
|
859
901
|
appId: z.string().describe('App Store ์ฑ ID'),
|
|
860
|
-
groupReferenceName: z
|
|
861
|
-
.string()
|
|
862
|
-
.describe("๊ตฌ๋
๊ทธ๋ฃน ๋ด๋ถ ์ด๋ฆ (์: 'premium'). ์์ผ๋ฉด ์๋ ์์ฑ, ์์ผ๋ฉด ๊ธฐ์กด ๊ทธ๋ฃน ์ฌ์ฌ์ฉ."),
|
|
863
902
|
productId: z.string().describe('๊ตฌ๋
productId (์: com.example.premium.monthly)'),
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
903
|
+
name: z.string().describe('๊ตฌ๋
์ด๋ฆ (์คํ ์ด ๋
ธ์ถ)'),
|
|
904
|
+
price: z.number().int().describe('๊ฐ๊ฒฉ (์ต์ ๋จ์: USD cents. ์: $9.99 โ 999, โฉ9,900 โ 9900)'),
|
|
905
|
+
currency: z.string().default('USD').describe('ISO 4217 ํตํ ์ฝ๋ (๊ธฐ๋ณธ USD)'),
|
|
906
|
+
period: z
|
|
907
|
+
.enum(['monthly', 'yearly'])
|
|
867
908
|
.describe('๊ตฌ๋
์ฃผ๊ธฐ'),
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
reviewNote: z.string().optional(),
|
|
874
|
-
familySharable: z.boolean().optional(),
|
|
875
|
-
groupLevel: z
|
|
876
|
-
.number()
|
|
909
|
+
extraRegions: z
|
|
910
|
+
.array(z.object({
|
|
911
|
+
currency: z.string().describe('ISO 4217 ํตํ ์ฝ๋ (์: KRW)'),
|
|
912
|
+
price: z.number().describe('๊ฐ๊ฒฉ (์ต์ ๋จ์)'),
|
|
913
|
+
}))
|
|
877
914
|
.optional()
|
|
878
|
-
.describe('
|
|
879
|
-
|
|
915
|
+
.describe('์ถ๊ฐ ์ง์ญ๋ณ ๋ช
์ ๊ฐ๊ฒฉ'),
|
|
916
|
+
bundleId: z.string().optional().describe('๋ฒ๋ค ID (appId ๋์ ์ฌ์ฉ ๊ฐ๋ฅ)'),
|
|
880
917
|
}, async (args) => {
|
|
881
|
-
const
|
|
882
|
-
const
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
918
|
+
const creds = requireAppStoreCreds();
|
|
919
|
+
const result = await createAppleSubscription({
|
|
920
|
+
appId: args.appId,
|
|
921
|
+
bundleId: args.bundleId,
|
|
922
|
+
productId: args.productId,
|
|
923
|
+
name: args.name,
|
|
924
|
+
price: args.price,
|
|
925
|
+
currency: args.currency,
|
|
926
|
+
period: args.period,
|
|
927
|
+
...(args.extraRegions && { extraRegions: args.extraRegions }),
|
|
928
|
+
keyId: creds.keyId,
|
|
929
|
+
issuerId: creds.issuerId,
|
|
930
|
+
privateKey: creds.privateKey,
|
|
931
|
+
});
|
|
932
|
+
if (!result.success) {
|
|
933
|
+
const hint = result.errorType === 'DUPLICATE'
|
|
934
|
+
? '\n์ด๋ฏธ ๊ฐ์ productId๊ฐ ์กด์ฌํด. App Store Connect์์ ํ์ธํด์ค.'
|
|
935
|
+
: result.errorType === 'PRICE_NOT_FOUND'
|
|
936
|
+
? `\n๊ฐ์ฅ ๊ฐ๊น์ด ๊ฐ๊ฒฉ: ${JSON.stringify(result.priceNearest)}`
|
|
937
|
+
: '';
|
|
938
|
+
return { content: [{ type: 'text', text: `โ ๊ตฌ๋
์์ฑ ์คํจ: ${result.error}${hint}` }] };
|
|
939
|
+
}
|
|
940
|
+
return {
|
|
941
|
+
content: [{
|
|
942
|
+
type: 'text',
|
|
943
|
+
text: [
|
|
944
|
+
`โ App Store ๊ตฌ๋
์์ฑ ์๋ฃ`,
|
|
945
|
+
`productId: ${result.productId}`,
|
|
946
|
+
`internalId: ${result.internalId}`,
|
|
947
|
+
result.priceSet ? `โ ๊ฐ๊ฒฉ ์ค์ ๋จ` : `โ ๊ฐ๊ฒฉ ๋ฏธ์ค์ (๊ฐ์ฅ ๊ฐ๊น์ด ๊ฐ๊ฒฉ: ${JSON.stringify(result.priceNearest)})`,
|
|
948
|
+
result.extraRegionsSet?.length ? `โ ์ถ๊ฐ ์ง์ญ: ${result.extraRegionsSet.join(', ')}` : '',
|
|
949
|
+
result.localizationAdded ? 'โ KRW ํ๊ตญ์ด ๋ก์ปฌ๋ผ์ด์ ์ด์
์ถ๊ฐ๋จ' : '',
|
|
950
|
+
'',
|
|
951
|
+
'App Store Connect์์ ์ฌ์ฌ ์ ์ถ:',
|
|
952
|
+
`https://appstoreconnect.apple.com/apps/${args.appId}/distribution/subscriptions`,
|
|
953
|
+
].filter(Boolean).join('\n'),
|
|
954
|
+
}],
|
|
955
|
+
};
|
|
956
|
+
});
|
|
957
|
+
// --- SKU ์ด์ (์กฐํ/์์ /์ญ์ ) โ onesub ์์ ---
|
|
958
|
+
server.tool('playstore_list_products', 'Google Play์ ๋ชจ๋ IAP ์ํ(๊ตฌ๋
+ ์ผํ์ฑ) ํตํฉ ์กฐํ. productId / name / status / type / price / currency ๋ฐํ.', {
|
|
959
|
+
packageName: z.string().describe('ํจํค์ง๋ช
'),
|
|
960
|
+
}, async ({ packageName }) => {
|
|
961
|
+
const json = requireServiceAccountJson();
|
|
962
|
+
const products = await listGoogleProducts({ packageName, serviceAccountKey: json });
|
|
963
|
+
return { content: [{ type: 'text', text: JSON.stringify(products, null, 2) }] };
|
|
964
|
+
});
|
|
965
|
+
server.tool('playstore_update_product', 'Google Play IAP ์ํ์ ํ์ ์ด๋ฆ ๋ณ๊ฒฝ (ํ์ฌ name ํ๋๋ง ์์ ๊ฐ๋ฅ). productId / type / ๊ฐ๊ฒฉ์ ๋ณ๊ฒฝ ๋ถ๊ฐ.', {
|
|
966
|
+
packageName: z.string().describe('ํจํค์ง๋ช
'),
|
|
967
|
+
productId: z.string().describe('์ํ ID'),
|
|
968
|
+
productType: z.enum(['subscription', 'consumable', 'non_consumable']).describe('์ํ ์ ํ'),
|
|
969
|
+
name: z.string().describe('์ ํ์ ์ด๋ฆ'),
|
|
970
|
+
}, async ({ packageName, productId, productType, name }) => {
|
|
971
|
+
const json = requireServiceAccountJson();
|
|
972
|
+
const result = await updateGoogleProduct({
|
|
973
|
+
packageName, productId, productType, name, serviceAccountKey: json,
|
|
974
|
+
});
|
|
975
|
+
if (!result.success) {
|
|
976
|
+
return { content: [{ type: 'text', text: `โ ์์ ์คํจ: ${result.error}` }] };
|
|
977
|
+
}
|
|
978
|
+
return { content: [{ type: 'text', text: `โ ์์ ์๋ฃ (๋ณ๊ฒฝ ํ๋: ${result.updated.join(', ') || 'none'})` }] };
|
|
979
|
+
});
|
|
980
|
+
server.tool('playstore_delete_product', 'โ ๏ธ ๋น๊ฐ์ญ. Google Play IAP ์ํ ์ญ์ . ํ์ฑ baseplan + ๊ตฌ๋
์ ์๋ ๊ตฌ๋
์ ์ญ์ ๋ถ๊ฐ.', {
|
|
981
|
+
packageName: z.string().describe('ํจํค์ง๋ช
'),
|
|
982
|
+
productId: z.string().describe('์ํ ID'),
|
|
983
|
+
productType: z.enum(['subscription', 'consumable', 'non_consumable']).describe('์ํ ์ ํ'),
|
|
984
|
+
}, async ({ packageName, productId, productType }) => {
|
|
985
|
+
const json = requireServiceAccountJson();
|
|
986
|
+
const result = await deleteGoogleProduct({
|
|
987
|
+
packageName, productId, productType, serviceAccountKey: json,
|
|
988
|
+
});
|
|
989
|
+
if (!result.success) {
|
|
990
|
+
return { content: [{ type: 'text', text: `โ ์ญ์ ์คํจ: ${result.error}` }] };
|
|
991
|
+
}
|
|
992
|
+
return { content: [{ type: 'text', text: `โ ${productId} ์ญ์ ์๋ฃ` }] };
|
|
993
|
+
});
|
|
994
|
+
server.tool('appstore_list_products', 'App Store์ ๋ชจ๋ IAP ์ํ(๊ตฌ๋
+ ์ผํ์ฑ) ํตํฉ ์กฐํ. productId / internalId / name / status / type ๋ฐํ.', {
|
|
995
|
+
appId: z.string().describe('App Store ์ฑ ID (์ซ์ํ, appstore_list_apps ๊ฒฐ๊ณผ)'),
|
|
996
|
+
}, async ({ appId }) => {
|
|
997
|
+
const creds = requireAppStoreCreds();
|
|
998
|
+
const products = await listAppleProducts({
|
|
999
|
+
appId, keyId: creds.keyId, issuerId: creds.issuerId, privateKey: creds.privateKey,
|
|
1000
|
+
});
|
|
1001
|
+
return { content: [{ type: 'text', text: JSON.stringify(products, null, 2) }] };
|
|
1002
|
+
});
|
|
1003
|
+
server.tool('appstore_update_product', 'App Store IAP ์ํ์ reference name ๋ณ๊ฒฝ. productId / ์ ํ์ ๋ณ๊ฒฝ ๋ถ๊ฐ.', {
|
|
1004
|
+
appId: z.string().optional().describe('App Store ์ฑ ID'),
|
|
1005
|
+
bundleId: z.string().optional().describe('๋ฒ๋ค ID (appId ๋์ ์ฌ์ฉ ๊ฐ๋ฅ)'),
|
|
1006
|
+
productId: z.string().describe('์ํ ID'),
|
|
1007
|
+
productType: z.enum(['subscription', 'consumable', 'non_consumable']).describe('์ํ ์ ํ'),
|
|
1008
|
+
name: z.string().describe('์ reference name'),
|
|
1009
|
+
}, async ({ appId, bundleId, productId, productType, name }) => {
|
|
1010
|
+
const creds = requireAppStoreCreds();
|
|
1011
|
+
const result = await updateAppleProduct({
|
|
1012
|
+
appId, bundleId, productId, productType, name,
|
|
1013
|
+
keyId: creds.keyId, issuerId: creds.issuerId, privateKey: creds.privateKey,
|
|
1014
|
+
});
|
|
1015
|
+
if (!result.success) {
|
|
1016
|
+
return { content: [{ type: 'text', text: `โ ์์ ์คํจ: ${result.error}` }] };
|
|
1017
|
+
}
|
|
1018
|
+
return { content: [{ type: 'text', text: `โ ์์ ์๋ฃ (๋ณ๊ฒฝ ํ๋: ${result.updated.join(', ') || 'none'})` }] };
|
|
1019
|
+
});
|
|
1020
|
+
server.tool('appstore_delete_product', 'โ ๏ธ ๋น๊ฐ์ญ. App Store IAP ์ํ ์ญ์ . MISSING_METADATA / WAITING_FOR_REVIEW ์ํ๋ง ๊ฐ๋ฅ โ ์ด๋ฏธ ์น์ธ(READY_FOR_SALE)๋ ์ํ์ Console์์ "Remove from sale" ํด์ผ ํจ.', {
|
|
1021
|
+
appId: z.string().optional().describe('App Store ์ฑ ID'),
|
|
1022
|
+
bundleId: z.string().optional().describe('๋ฒ๋ค ID (appId ๋์ ์ฌ์ฉ ๊ฐ๋ฅ)'),
|
|
1023
|
+
productId: z.string().describe('์ํ ID'),
|
|
1024
|
+
productType: z.enum(['subscription', 'consumable', 'non_consumable']).describe('์ํ ์ ํ'),
|
|
1025
|
+
}, async ({ appId, bundleId, productId, productType }) => {
|
|
1026
|
+
const creds = requireAppStoreCreds();
|
|
1027
|
+
const result = await deleteAppleProduct({
|
|
1028
|
+
appId, bundleId, productId, productType,
|
|
1029
|
+
keyId: creds.keyId, issuerId: creds.issuerId, privateKey: creds.privateKey,
|
|
1030
|
+
});
|
|
1031
|
+
if (!result.success) {
|
|
1032
|
+
const hint = result.errorType === 'CANNOT_DELETE'
|
|
1033
|
+
? '\n์น์ธ๋ ์ํ์ API ์ญ์ ๋ถ๊ฐ โ App Store Connect โ ์ํ โ "Remove from sale"'
|
|
1034
|
+
: '';
|
|
1035
|
+
return { content: [{ type: 'text', text: `โ ์ญ์ ์คํจ: ${result.error}${hint}` }] };
|
|
1036
|
+
}
|
|
1037
|
+
return { content: [{ type: 'text', text: `โ ${productId} ์ญ์ ์๋ฃ` }] };
|
|
908
1038
|
});
|
|
909
1039
|
// --- App Store ์ฌ์ฌ ์ ์ถ (Submit for Review) ---
|
|
910
1040
|
server.tool('appstore_submit_for_review', [
|
|
@@ -932,7 +1062,7 @@ server.tool('playstore_submit_release', [
|
|
|
932
1062
|
versionCode: z.string().describe('๋์ versionCode (๋ฌธ์์ด)'),
|
|
933
1063
|
status: z.enum(['draft', 'inProgress', 'completed', 'halted']).optional().describe('์ status (๊ธฐ๋ณธ: completed)'),
|
|
934
1064
|
}, async ({ packageName, track, versionCode, status }) => {
|
|
935
|
-
const auth =
|
|
1065
|
+
const auth = requirePlayStoreAuth();
|
|
936
1066
|
const result = await playstore.submitRelease(auth, packageName, track, versionCode, status);
|
|
937
1067
|
return { content: [{ type: 'text', text: `โ
${packageName} ${track} v${versionCode}: ${result.previousStatus} โ ${result.newStatus}\n\n${JSON.stringify(result, null, 2)}` }] };
|
|
938
1068
|
});
|
|
@@ -958,7 +1088,7 @@ server.tool('playstore_promote_release', [
|
|
|
958
1088
|
text: z.string().describe('๋ฆด๋ฆฌ์ค ๋
ธํธ ๋ณธ๋ฌธ (500์ ์ด๋ด)'),
|
|
959
1089
|
})).optional().describe('๋์ ํธ๋์ฉ ๋ฆด๋ฆฌ์ค ๋
ธํธ (๋ฏธ์ง์ + copyReleaseNotes=true๋ฉด source ๊ทธ๋๋ก)'),
|
|
960
1090
|
}, async ({ packageName, fromTrack, toTrack, versionCode, status, userFraction, releaseName, copyReleaseNotes, releaseNotes }) => {
|
|
961
|
-
const auth =
|
|
1091
|
+
const auth = requirePlayStoreAuth();
|
|
962
1092
|
const result = await playstore.promoteRelease(auth, packageName, fromTrack, toTrack, versionCode, {
|
|
963
1093
|
status,
|
|
964
1094
|
userFraction,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { OAuth2Client } from 'google-auth-library';
|
|
2
|
+
import { JWT } from 'google-auth-library';
|
|
2
3
|
export type PlayImageType = 'featureGraphic' | 'icon' | 'phoneScreenshots' | 'promoGraphic' | 'sevenInchScreenshots' | 'tenInchScreenshots' | 'tvBanner' | 'tvScreenshots' | 'wearScreenshots';
|
|
3
4
|
/**
|
|
4
5
|
* Google Play Developer API (Android Publisher API v3) ๋ํผ
|
|
@@ -7,15 +8,15 @@ export type PlayImageType = 'featureGraphic' | 'icon' | 'phoneScreenshots' | 'pr
|
|
|
7
8
|
* ์ฌ๊ธฐ์๋ ๊ธฐ์กด ์ฑ์ ๋ฉํ๋ฐ์ดํฐ, ๋น๋, ์ถ์๋ฅผ ๊ด๋ฆฌ.
|
|
8
9
|
*/
|
|
9
10
|
export declare const publisher: () => import("googleapis").androidpublisher_v3.Androidpublisher;
|
|
10
|
-
export declare function withEdit<T>(auth: OAuth2Client, packageName: string, fn: (editId: string) => Promise<T>, commit?: boolean): Promise<T>;
|
|
11
|
-
export declare function getAppDetails(auth: OAuth2Client, packageName: string): Promise<import("googleapis").androidpublisher_v3.Schema$AppDetails>;
|
|
12
|
-
export declare function getListing(auth: OAuth2Client, packageName: string, language?: string): Promise<import("googleapis").androidpublisher_v3.Schema$Listing>;
|
|
13
|
-
export declare function updateListing(auth: OAuth2Client, packageName: string, language: string, data: {
|
|
11
|
+
export declare function withEdit<T>(auth: OAuth2Client | JWT, packageName: string, fn: (editId: string) => Promise<T>, commit?: boolean): Promise<T>;
|
|
12
|
+
export declare function getAppDetails(auth: OAuth2Client | JWT, packageName: string): Promise<import("googleapis").androidpublisher_v3.Schema$AppDetails>;
|
|
13
|
+
export declare function getListing(auth: OAuth2Client | JWT, packageName: string, language?: string): Promise<import("googleapis").androidpublisher_v3.Schema$Listing>;
|
|
14
|
+
export declare function updateListing(auth: OAuth2Client | JWT, packageName: string, language: string, data: {
|
|
14
15
|
title?: string;
|
|
15
16
|
shortDescription?: string;
|
|
16
17
|
fullDescription?: string;
|
|
17
18
|
}): Promise<import("googleapis").androidpublisher_v3.Schema$Listing>;
|
|
18
|
-
export declare function listTracks(auth: OAuth2Client, packageName: string): Promise<{
|
|
19
|
+
export declare function listTracks(auth: OAuth2Client | JWT, packageName: string): Promise<{
|
|
19
20
|
track: string | null | undefined;
|
|
20
21
|
releases: {
|
|
21
22
|
name: string | null | undefined;
|
|
@@ -24,20 +25,20 @@ export declare function listTracks(auth: OAuth2Client, packageName: string): Pro
|
|
|
24
25
|
releaseNotes: import("googleapis").androidpublisher_v3.Schema$LocalizedText[] | undefined;
|
|
25
26
|
}[];
|
|
26
27
|
}[]>;
|
|
27
|
-
export declare function updateReleaseNotes(auth: OAuth2Client, packageName: string, track: string, versionCode: string, language: string, text: string): Promise<import("googleapis").androidpublisher_v3.Schema$Track>;
|
|
28
|
+
export declare function updateReleaseNotes(auth: OAuth2Client | JWT, packageName: string, track: string, versionCode: string, language: string, text: string): Promise<import("googleapis").androidpublisher_v3.Schema$Track>;
|
|
28
29
|
/**
|
|
29
30
|
* ์ต์ release (versionCode ์ต๋๊ฐ)์ releaseNotes[language]๋ฅผ ๊ต์ฒด/์ถ๊ฐ.
|
|
30
31
|
* versionCode๋ฅผ ๋ชจ๋ฅผ ๋ ํธ์์ฉ.
|
|
31
32
|
*/
|
|
32
|
-
export declare function updateLatestReleaseNotes(auth: OAuth2Client, packageName: string, track: string, language: string, text: string): Promise<{
|
|
33
|
+
export declare function updateLatestReleaseNotes(auth: OAuth2Client | JWT, packageName: string, track: string, language: string, text: string): Promise<{
|
|
33
34
|
updatedVersionCodes: string[] | null | undefined;
|
|
34
35
|
updatedReleaseName: string | null | undefined;
|
|
35
36
|
releases?: import("googleapis").androidpublisher_v3.Schema$TrackRelease[];
|
|
36
37
|
track?: string | null;
|
|
37
38
|
}>;
|
|
38
|
-
export declare function listImages(auth: OAuth2Client, packageName: string, language: string, imageType: PlayImageType): Promise<import("googleapis").androidpublisher_v3.Schema$Image[]>;
|
|
39
|
-
export declare function uploadImage(auth: OAuth2Client, packageName: string, language: string, imageType: PlayImageType, filePath: string): Promise<import("googleapis").androidpublisher_v3.Schema$Image | undefined>;
|
|
40
|
-
export declare function deleteAllImages(auth: OAuth2Client, packageName: string, language: string, imageType: PlayImageType): Promise<{
|
|
39
|
+
export declare function listImages(auth: OAuth2Client | JWT, packageName: string, language: string, imageType: PlayImageType): Promise<import("googleapis").androidpublisher_v3.Schema$Image[]>;
|
|
40
|
+
export declare function uploadImage(auth: OAuth2Client | JWT, packageName: string, language: string, imageType: PlayImageType, filePath: string): Promise<import("googleapis").androidpublisher_v3.Schema$Image | undefined>;
|
|
41
|
+
export declare function deleteAllImages(auth: OAuth2Client | JWT, packageName: string, language: string, imageType: PlayImageType): Promise<{
|
|
41
42
|
ok: boolean;
|
|
42
43
|
imageType: PlayImageType;
|
|
43
44
|
}>;
|
|
@@ -45,7 +46,7 @@ export declare function deleteAllImages(auth: OAuth2Client, packageName: string,
|
|
|
45
46
|
* ํ edit ์ธ์
๋ด์์ ๊ธฐ์กด ์ด๋ฏธ์ง ์ ์ฒด ์ญ์ + ์ ์ด๋ฏธ์ง ์์๋๋ก ์
๋ก๋ + commit.
|
|
46
47
|
* phoneScreenshots์ฒ๋ผ ์ฌ๋ฌ ์ฅ ๊ต์ฒด ์ ํจ์จ์ (๋จ์ผ edit).
|
|
47
48
|
*/
|
|
48
|
-
export declare function replaceImages(auth: OAuth2Client, packageName: string, language: string, imageType: PlayImageType, filePaths: string[]): Promise<{
|
|
49
|
+
export declare function replaceImages(auth: OAuth2Client | JWT, packageName: string, language: string, imageType: PlayImageType, filePaths: string[]): Promise<{
|
|
49
50
|
imageType: PlayImageType;
|
|
50
51
|
count: number;
|
|
51
52
|
uploaded: {
|
|
@@ -54,7 +55,7 @@ export declare function replaceImages(auth: OAuth2Client, packageName: string, l
|
|
|
54
55
|
sha256?: string | null;
|
|
55
56
|
}[];
|
|
56
57
|
}>;
|
|
57
|
-
export declare function submitRelease(auth: OAuth2Client, packageName: string, track: string, versionCode: string, status?: 'completed' | 'draft' | 'inProgress' | 'halted'): Promise<{
|
|
58
|
+
export declare function submitRelease(auth: OAuth2Client | JWT, packageName: string, track: string, versionCode: string, status?: 'completed' | 'draft' | 'inProgress' | 'halted'): Promise<{
|
|
58
59
|
track: string;
|
|
59
60
|
versionCode: string;
|
|
60
61
|
previousStatus: string | null | undefined;
|
|
@@ -72,7 +73,7 @@ export interface PromoteReleaseOptions {
|
|
|
72
73
|
}>;
|
|
73
74
|
copyReleaseNotes?: boolean;
|
|
74
75
|
}
|
|
75
|
-
export declare function promoteRelease(auth: OAuth2Client, packageName: string, fromTrack: string, toTrack: string, versionCode: string, options?: PromoteReleaseOptions): Promise<{
|
|
76
|
+
export declare function promoteRelease(auth: OAuth2Client | JWT, packageName: string, fromTrack: string, toTrack: string, versionCode: string, options?: PromoteReleaseOptions): Promise<{
|
|
76
77
|
packageName: string;
|
|
77
78
|
fromTrack: string;
|
|
78
79
|
toTrack: string;
|
|
@@ -84,7 +85,7 @@ export declare function promoteRelease(auth: OAuth2Client, packageName: string,
|
|
|
84
85
|
committed: boolean;
|
|
85
86
|
result: import("googleapis").androidpublisher_v3.Schema$Track;
|
|
86
87
|
}>;
|
|
87
|
-
export declare function listReviews(auth: OAuth2Client, packageName: string): Promise<{
|
|
88
|
+
export declare function listReviews(auth: OAuth2Client | JWT, packageName: string): Promise<{
|
|
88
89
|
reviewId: string | null | undefined;
|
|
89
90
|
authorName: string | null | undefined;
|
|
90
91
|
comments: {
|
|
@@ -94,59 +95,17 @@ export declare function listReviews(auth: OAuth2Client, packageName: string): Pr
|
|
|
94
95
|
deviceMetadata: string | null | undefined;
|
|
95
96
|
}[] | undefined;
|
|
96
97
|
}[]>;
|
|
97
|
-
export declare function replyToReview(auth: OAuth2Client, packageName: string, reviewId: string, replyText: string): Promise<import("googleapis").androidpublisher_v3.Schema$ReviewsReplyResponse>;
|
|
98
|
-
export declare function listInAppProducts(auth: OAuth2Client, packageName: string): Promise<{
|
|
98
|
+
export declare function replyToReview(auth: OAuth2Client | JWT, packageName: string, reviewId: string, replyText: string): Promise<import("googleapis").androidpublisher_v3.Schema$ReviewsReplyResponse>;
|
|
99
|
+
export declare function listInAppProducts(auth: OAuth2Client | JWT, packageName: string): Promise<{
|
|
99
100
|
productId: any;
|
|
100
101
|
listings: any;
|
|
101
102
|
purchaseOptions: any;
|
|
102
103
|
}[]>;
|
|
103
|
-
export declare function listSubscriptions(auth: OAuth2Client, packageName: string): Promise<{
|
|
104
|
+
export declare function listSubscriptions(auth: OAuth2Client | JWT, packageName: string): Promise<{
|
|
104
105
|
productId: string | null | undefined;
|
|
105
106
|
basePlans: import("googleapis").androidpublisher_v3.Schema$BasePlan[] | undefined;
|
|
106
107
|
listings: import("googleapis").androidpublisher_v3.Schema$SubscriptionListing[] | undefined;
|
|
107
108
|
}[]>;
|
|
108
|
-
export interface CreateOneTimeProductInput {
|
|
109
|
-
packageName: string;
|
|
110
|
-
productId: string;
|
|
111
|
-
title: string;
|
|
112
|
-
description: string;
|
|
113
|
-
languageCode?: string;
|
|
114
|
-
priceUsd: number;
|
|
115
|
-
purchaseOptionId?: string;
|
|
116
|
-
legacyCompatible?: boolean;
|
|
117
|
-
regionsVersion?: string;
|
|
118
|
-
newRegionsPricing?: {
|
|
119
|
-
usdPrice: number;
|
|
120
|
-
eurPrice: number;
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
export declare function createOnetimeProduct(auth: OAuth2Client, input: CreateOneTimeProductInput): Promise<import("googleapis").androidpublisher_v3.Schema$OneTimeProduct>;
|
|
124
|
-
export interface CreateSubscriptionInput {
|
|
125
|
-
packageName: string;
|
|
126
|
-
productId: string;
|
|
127
|
-
title: string;
|
|
128
|
-
description: string;
|
|
129
|
-
benefits?: string[];
|
|
130
|
-
languageCode?: string;
|
|
131
|
-
basePlanId?: string;
|
|
132
|
-
billingPeriod: 'P1W' | 'P1M' | 'P3M' | 'P6M' | 'P1Y';
|
|
133
|
-
priceUsd: number;
|
|
134
|
-
gracePeriod?: 'P0D' | 'P3D' | 'P7D' | 'P14D' | 'P30D';
|
|
135
|
-
resubscribeState?: 'RESUBSCRIBE_STATE_ACTIVE' | 'RESUBSCRIBE_STATE_INACTIVE';
|
|
136
|
-
autoActivate?: boolean;
|
|
137
|
-
regionsVersion?: string;
|
|
138
|
-
newRegionsPricing?: {
|
|
139
|
-
usdPrice: number;
|
|
140
|
-
eurPrice: number;
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
export declare function createSubscription(auth: OAuth2Client, input: CreateSubscriptionInput): Promise<{
|
|
144
|
-
productId: string;
|
|
145
|
-
basePlanId: string;
|
|
146
|
-
basePlanState?: string | null;
|
|
147
|
-
activated: boolean;
|
|
148
|
-
activateError?: string;
|
|
149
|
-
}>;
|
|
150
109
|
export type ServiceAccountVerifyResult = {
|
|
151
110
|
ok: true;
|
|
152
111
|
clientEmail: string;
|
package/dist/playstore/tools.js
CHANGED
|
@@ -384,166 +384,6 @@ export async function listSubscriptions(auth, packageName) {
|
|
|
384
384
|
listings: s.listings,
|
|
385
385
|
}));
|
|
386
386
|
}
|
|
387
|
-
function moneyFromNumber(amount, currencyCode) {
|
|
388
|
-
const units = Math.trunc(amount).toString();
|
|
389
|
-
const nanos = Math.round((amount - Math.trunc(amount)) * 1_000_000_000);
|
|
390
|
-
return { currencyCode, units, nanos };
|
|
391
|
-
}
|
|
392
|
-
export async function createOnetimeProduct(auth, input) {
|
|
393
|
-
const languageCode = input.languageCode ?? 'en-US';
|
|
394
|
-
const purchaseOptionId = input.purchaseOptionId ?? 'default-buy';
|
|
395
|
-
const regionsVersion = input.regionsVersion ?? '2022/02';
|
|
396
|
-
const usdPrice = moneyFromNumber(input.priceUsd, 'USD');
|
|
397
|
-
const newRegionsConfig = input.newRegionsPricing
|
|
398
|
-
? {
|
|
399
|
-
availability: 'AVAILABLE',
|
|
400
|
-
usdPrice: moneyFromNumber(input.newRegionsPricing.usdPrice, 'USD'),
|
|
401
|
-
eurPrice: moneyFromNumber(input.newRegionsPricing.eurPrice, 'EUR'),
|
|
402
|
-
}
|
|
403
|
-
: { availability: 'UNAVAILABLE' };
|
|
404
|
-
const res = await publisher().monetization.onetimeproducts.patch({
|
|
405
|
-
auth,
|
|
406
|
-
packageName: input.packageName,
|
|
407
|
-
productId: input.productId,
|
|
408
|
-
allowMissing: true,
|
|
409
|
-
updateMask: 'listings,purchaseOptions',
|
|
410
|
-
'regionsVersion.version': regionsVersion,
|
|
411
|
-
requestBody: {
|
|
412
|
-
packageName: input.packageName,
|
|
413
|
-
productId: input.productId,
|
|
414
|
-
listings: [
|
|
415
|
-
{
|
|
416
|
-
languageCode,
|
|
417
|
-
title: input.title,
|
|
418
|
-
description: input.description,
|
|
419
|
-
},
|
|
420
|
-
],
|
|
421
|
-
purchaseOptions: [
|
|
422
|
-
{
|
|
423
|
-
purchaseOptionId,
|
|
424
|
-
buyOption: {
|
|
425
|
-
legacyCompatible: input.legacyCompatible ?? true,
|
|
426
|
-
},
|
|
427
|
-
regionalPricingAndAvailabilityConfigs: [
|
|
428
|
-
{
|
|
429
|
-
regionCode: 'US',
|
|
430
|
-
availability: 'AVAILABLE',
|
|
431
|
-
price: usdPrice,
|
|
432
|
-
},
|
|
433
|
-
],
|
|
434
|
-
newRegionsConfig,
|
|
435
|
-
},
|
|
436
|
-
],
|
|
437
|
-
},
|
|
438
|
-
});
|
|
439
|
-
return res.data;
|
|
440
|
-
}
|
|
441
|
-
function defaultBasePlanIdFor(period) {
|
|
442
|
-
switch (period) {
|
|
443
|
-
case 'P1W': return 'weekly';
|
|
444
|
-
case 'P1M': return 'monthly';
|
|
445
|
-
case 'P3M': return 'quarterly';
|
|
446
|
-
case 'P6M': return 'semi-yearly';
|
|
447
|
-
case 'P1Y': return 'yearly';
|
|
448
|
-
default: return 'default';
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
export async function createSubscription(auth, input) {
|
|
452
|
-
const languageCode = input.languageCode ?? 'en-US';
|
|
453
|
-
const basePlanId = input.basePlanId ?? defaultBasePlanIdFor(input.billingPeriod);
|
|
454
|
-
const regionsVersion = input.regionsVersion ?? '2022/02';
|
|
455
|
-
const usdPrice = moneyFromNumber(input.priceUsd, 'USD');
|
|
456
|
-
const otherRegionsConfig = input.newRegionsPricing
|
|
457
|
-
? {
|
|
458
|
-
newSubscriberAvailability: true,
|
|
459
|
-
usdPrice: moneyFromNumber(input.newRegionsPricing.usdPrice, 'USD'),
|
|
460
|
-
eurPrice: moneyFromNumber(input.newRegionsPricing.eurPrice, 'EUR'),
|
|
461
|
-
}
|
|
462
|
-
: { newSubscriberAvailability: false };
|
|
463
|
-
// 1) subscription ์
ธ upsert (allowMissing=true๋ก idempotent)
|
|
464
|
-
// updateMask๋ mutable ํ๋๋ง โ packageName/productId๋ immutable์ด๋ผ ํฌํจ ์ reject ๊ฐ๋ฅ.
|
|
465
|
-
await publisher().monetization.subscriptions.patch({
|
|
466
|
-
auth,
|
|
467
|
-
packageName: input.packageName,
|
|
468
|
-
productId: input.productId,
|
|
469
|
-
allowMissing: true,
|
|
470
|
-
updateMask: 'listings',
|
|
471
|
-
'regionsVersion.version': regionsVersion,
|
|
472
|
-
requestBody: {
|
|
473
|
-
packageName: input.packageName,
|
|
474
|
-
productId: input.productId,
|
|
475
|
-
listings: [
|
|
476
|
-
{
|
|
477
|
-
languageCode,
|
|
478
|
-
title: input.title,
|
|
479
|
-
description: input.description,
|
|
480
|
-
benefits: input.benefits,
|
|
481
|
-
},
|
|
482
|
-
],
|
|
483
|
-
},
|
|
484
|
-
});
|
|
485
|
-
// 2) basePlan ์์ฑ (์ด๋ฏธ ์์ผ๋ฉด conflict โ ๊ทธ๋ update ์๋)
|
|
486
|
-
let basePlanState;
|
|
487
|
-
try {
|
|
488
|
-
const created = await publisher().monetization.subscriptions.basePlans.create({
|
|
489
|
-
auth,
|
|
490
|
-
packageName: input.packageName,
|
|
491
|
-
productId: input.productId,
|
|
492
|
-
basePlanId,
|
|
493
|
-
'regionsVersion.version': regionsVersion,
|
|
494
|
-
requestBody: {
|
|
495
|
-
basePlanId,
|
|
496
|
-
autoRenewingBasePlanType: {
|
|
497
|
-
billingPeriodDuration: input.billingPeriod,
|
|
498
|
-
gracePeriodDuration: input.gracePeriod ?? 'P7D',
|
|
499
|
-
resubscribeState: input.resubscribeState ?? 'RESUBSCRIBE_STATE_ACTIVE',
|
|
500
|
-
},
|
|
501
|
-
regionalConfigs: [
|
|
502
|
-
{
|
|
503
|
-
regionCode: 'US',
|
|
504
|
-
newSubscriberAvailability: true,
|
|
505
|
-
price: usdPrice,
|
|
506
|
-
},
|
|
507
|
-
],
|
|
508
|
-
otherRegionsConfig,
|
|
509
|
-
},
|
|
510
|
-
});
|
|
511
|
-
basePlanState = created.data?.state;
|
|
512
|
-
}
|
|
513
|
-
catch (err) {
|
|
514
|
-
// ์ด๋ฏธ ์กด์ฌํ๋ ๊ฒฝ์ฐ 409 โ ๊ทธ๋ฅ ์งํ
|
|
515
|
-
const e = err;
|
|
516
|
-
if (e.code !== 409 && e.status !== 409) {
|
|
517
|
-
throw err;
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
// 3) ์๋ ํ์ฑํ (์ต์
)
|
|
521
|
-
let activated = false;
|
|
522
|
-
let activateError;
|
|
523
|
-
if (input.autoActivate !== false) {
|
|
524
|
-
try {
|
|
525
|
-
const activated_ = await publisher().monetization.subscriptions.basePlans.activate({
|
|
526
|
-
auth,
|
|
527
|
-
packageName: input.packageName,
|
|
528
|
-
productId: input.productId,
|
|
529
|
-
basePlanId,
|
|
530
|
-
requestBody: {},
|
|
531
|
-
});
|
|
532
|
-
activated = true;
|
|
533
|
-
basePlanState = (activated_.data?.basePlans?.find?.((b) => b.basePlanId === basePlanId)?.state) ?? basePlanState;
|
|
534
|
-
}
|
|
535
|
-
catch (err) {
|
|
536
|
-
activateError = err.message;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
return {
|
|
540
|
-
productId: input.productId,
|
|
541
|
-
basePlanId,
|
|
542
|
-
basePlanState,
|
|
543
|
-
activated,
|
|
544
|
-
activateError,
|
|
545
|
-
};
|
|
546
|
-
}
|
|
547
387
|
export async function verifyServiceAccountJson(serviceAccountJson, packageName) {
|
|
548
388
|
let parsed;
|
|
549
389
|
try {
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yoonion/mimi-seed-mcp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
4
4
|
"description": "Mimi Seed MCP server โ Firebase + AdMob + Google Play + App Store management for Claude Code / Cursor / any MCP client.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"mimi-seed-mcp": "dist/index.js",
|
|
8
8
|
"mimi-seed-auth": "dist/auth/cli.js",
|
|
9
|
-
"mimi-seed-appstore-auth": "dist/appstore/setup-cli.js"
|
|
9
|
+
"mimi-seed-appstore-auth": "dist/appstore/setup-cli.js",
|
|
10
|
+
"mimi-seed-playstore-auth": "dist/auth/playstore-setup-cli.js"
|
|
10
11
|
},
|
|
11
12
|
"files": [
|
|
12
13
|
"dist"
|
|
@@ -44,6 +45,7 @@
|
|
|
44
45
|
"dependencies": {
|
|
45
46
|
"@anthropic-ai/sdk": "^0.52.0",
|
|
46
47
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
48
|
+
"@onesub/providers": "^0.2.0",
|
|
47
49
|
"googleapis": "^171.4.0",
|
|
48
50
|
"jsonwebtoken": "^9.0.3",
|
|
49
51
|
"open": "^10.1.0",
|