@akoskomuves/appstoreconnect-mcp 0.1.1
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/CHANGELOG.md +74 -0
- package/LICENSE +21 -0
- package/README.md +158 -0
- package/data/apple-music-prices.json +78 -0
- package/dist/auth.d.ts +9 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +33 -0
- package/dist/auth.js.map +1 -0
- package/dist/client.d.ts +6 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +75 -0
- package/dist/client.js.map +1 -0
- package/dist/clients.d.ts +31 -0
- package/dist/clients.d.ts.map +1 -0
- package/dist/clients.js +88 -0
- package/dist/clients.js.map +1 -0
- package/dist/config.d.ts +7 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +29 -0
- package/dist/config.js.map +1 -0
- package/dist/digest.d.ts +13 -0
- package/dist/digest.d.ts.map +1 -0
- package/dist/digest.js +154 -0
- package/dist/digest.js.map +1 -0
- package/dist/doctor.d.ts +2 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +139 -0
- package/dist/doctor.js.map +1 -0
- package/dist/domains/apps.d.ts +4 -0
- package/dist/domains/apps.d.ts.map +1 -0
- package/dist/domains/apps.js +40 -0
- package/dist/domains/apps.js.map +1 -0
- package/dist/domains/ppp.d.ts +6 -0
- package/dist/domains/ppp.d.ts.map +1 -0
- package/dist/domains/ppp.js +539 -0
- package/dist/domains/ppp.js.map +1 -0
- package/dist/domains/pricing.d.ts +4 -0
- package/dist/domains/pricing.d.ts.map +1 -0
- package/dist/domains/pricing.js +55 -0
- package/dist/domains/pricing.js.map +1 -0
- package/dist/domains/subscriptions.d.ts +4 -0
- package/dist/domains/subscriptions.d.ts.map +1 -0
- package/dist/domains/subscriptions.js +84 -0
- package/dist/domains/subscriptions.js.map +1 -0
- package/dist/domains/territories.d.ts +4 -0
- package/dist/domains/territories.d.ts.map +1 -0
- package/dist/domains/territories.js +21 -0
- package/dist/domains/territories.js.map +1 -0
- package/dist/errors.d.ts +6 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +11 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +98 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +6 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +316 -0
- package/dist/init.js.map +1 -0
- package/dist/jsonapi.d.ts +62 -0
- package/dist/jsonapi.d.ts.map +1 -0
- package/dist/jsonapi.js +78 -0
- package/dist/jsonapi.js.map +1 -0
- package/dist/ppp/index.d.ts +40 -0
- package/dist/ppp/index.d.ts.map +1 -0
- package/dist/ppp/index.js +85 -0
- package/dist/ppp/index.js.map +1 -0
- package/dist/schemas.d.ts +10 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +34 -0
- package/dist/schemas.js.map +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { ASCClient } from './client.js';
|
|
2
|
+
export interface JSONAPIResource {
|
|
3
|
+
type: string;
|
|
4
|
+
id: string;
|
|
5
|
+
attributes?: Record<string, unknown>;
|
|
6
|
+
relationships?: Record<string, JSONAPIRelationship>;
|
|
7
|
+
}
|
|
8
|
+
export interface JSONAPIRelationship {
|
|
9
|
+
data?: {
|
|
10
|
+
type: string;
|
|
11
|
+
id: string;
|
|
12
|
+
} | Array<{
|
|
13
|
+
type: string;
|
|
14
|
+
id: string;
|
|
15
|
+
}> | null;
|
|
16
|
+
links?: {
|
|
17
|
+
self?: string;
|
|
18
|
+
related?: string;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export interface JSONAPIResponse<T = JSONAPIResource | JSONAPIResource[]> {
|
|
22
|
+
data: T;
|
|
23
|
+
included?: JSONAPIResource[];
|
|
24
|
+
links?: {
|
|
25
|
+
self?: string;
|
|
26
|
+
next?: string;
|
|
27
|
+
prev?: string;
|
|
28
|
+
first?: string;
|
|
29
|
+
last?: string;
|
|
30
|
+
};
|
|
31
|
+
meta?: {
|
|
32
|
+
paging?: {
|
|
33
|
+
total?: number;
|
|
34
|
+
limit?: number;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export interface CollectedPages {
|
|
39
|
+
data: JSONAPIResource[];
|
|
40
|
+
included: JSONAPIResource[];
|
|
41
|
+
total?: number;
|
|
42
|
+
pagesFetched: number;
|
|
43
|
+
truncated: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Auto-paginate an ASC list endpoint. Follows `links.next` until exhausted
|
|
47
|
+
* or `maxItems` is reached, dedupes `included` resources by `${type}/${id}`,
|
|
48
|
+
* and returns the merged collection.
|
|
49
|
+
*/
|
|
50
|
+
export declare function paginate(client: ASCClient, initialPath: string, maxItems?: number): Promise<CollectedPages>;
|
|
51
|
+
export declare function buildIncludedIndex(included: JSONAPIResource[]): Map<string, JSONAPIResource>;
|
|
52
|
+
export declare function lookupIncluded(index: Map<string, JSONAPIResource>, type: string, id: string | undefined): JSONAPIResource | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* Right-pad / left-pad columns to align rows. Numeric columns can be marked
|
|
55
|
+
* with `align: 'right'` for trailing-decimal alignment.
|
|
56
|
+
*/
|
|
57
|
+
export interface Column {
|
|
58
|
+
header: string;
|
|
59
|
+
align?: 'left' | 'right';
|
|
60
|
+
}
|
|
61
|
+
export declare function formatTable(columns: Column[], rows: string[][]): string;
|
|
62
|
+
//# sourceMappingURL=jsonapi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonapi.d.ts","sourceRoot":"","sources":["../src/jsonapi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC;IACjF,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC7C;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,eAAe,GAAG,eAAe,EAAE;IACtE,IAAI,EAAE,CAAC,CAAC;IACR,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvF,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,CAAC;YAAC,KAAK,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;CACxD;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,eAAe,EAAE,CAAC;IACxB,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,OAAO,CAAC;CACpB;AAID;;;;GAIG;AACH,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,SAAS,EACjB,WAAW,EAAE,MAAM,EACnB,QAAQ,SAAO,GACd,OAAO,CAAC,cAAc,CAAC,CAsCzB;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,eAAe,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAM5F;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,EACnC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,GAAG,SAAS,GACrB,eAAe,GAAG,SAAS,CAG7B;AAED;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,CAmBvE"}
|
package/dist/jsonapi.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const PAGE_HARD_CAP = 50;
|
|
2
|
+
/**
|
|
3
|
+
* Auto-paginate an ASC list endpoint. Follows `links.next` until exhausted
|
|
4
|
+
* or `maxItems` is reached, dedupes `included` resources by `${type}/${id}`,
|
|
5
|
+
* and returns the merged collection.
|
|
6
|
+
*/
|
|
7
|
+
export async function paginate(client, initialPath, maxItems = 1000) {
|
|
8
|
+
const data = [];
|
|
9
|
+
const includedMap = new Map();
|
|
10
|
+
let total;
|
|
11
|
+
let next = initialPath;
|
|
12
|
+
let pagesFetched = 0;
|
|
13
|
+
let truncated = false;
|
|
14
|
+
while (next && pagesFetched < PAGE_HARD_CAP) {
|
|
15
|
+
const page = await client.request(next);
|
|
16
|
+
pagesFetched += 1;
|
|
17
|
+
if (Array.isArray(page.data)) {
|
|
18
|
+
for (const r of page.data) {
|
|
19
|
+
if (data.length >= maxItems) {
|
|
20
|
+
truncated = true;
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
data.push(r);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
for (const r of page.included ?? []) {
|
|
27
|
+
const key = `${r.type}/${r.id}`;
|
|
28
|
+
if (!includedMap.has(key))
|
|
29
|
+
includedMap.set(key, r);
|
|
30
|
+
}
|
|
31
|
+
if (page.meta?.paging?.total !== undefined)
|
|
32
|
+
total = page.meta.paging.total;
|
|
33
|
+
if (truncated)
|
|
34
|
+
break;
|
|
35
|
+
next = page.links?.next ?? null;
|
|
36
|
+
}
|
|
37
|
+
if (next)
|
|
38
|
+
truncated = true;
|
|
39
|
+
return {
|
|
40
|
+
data,
|
|
41
|
+
included: Array.from(includedMap.values()),
|
|
42
|
+
...(total !== undefined ? { total } : {}),
|
|
43
|
+
pagesFetched,
|
|
44
|
+
truncated,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export function buildIncludedIndex(included) {
|
|
48
|
+
const map = new Map();
|
|
49
|
+
for (const r of included) {
|
|
50
|
+
map.set(`${r.type}/${r.id}`, r);
|
|
51
|
+
}
|
|
52
|
+
return map;
|
|
53
|
+
}
|
|
54
|
+
export function lookupIncluded(index, type, id) {
|
|
55
|
+
if (!id)
|
|
56
|
+
return undefined;
|
|
57
|
+
return index.get(`${type}/${id}`);
|
|
58
|
+
}
|
|
59
|
+
export function formatTable(columns, rows) {
|
|
60
|
+
const widths = columns.map((c, i) => {
|
|
61
|
+
let w = c.header.length;
|
|
62
|
+
for (const row of rows) {
|
|
63
|
+
const cell = row[i] ?? '';
|
|
64
|
+
if (cell.length > w)
|
|
65
|
+
w = cell.length;
|
|
66
|
+
}
|
|
67
|
+
return w;
|
|
68
|
+
});
|
|
69
|
+
const pad = (cell, width, align) => align === 'right' ? cell.padStart(width) : cell.padEnd(width);
|
|
70
|
+
const renderRow = (cells) => columns
|
|
71
|
+
.map((c, i) => pad(cells[i] ?? '', widths[i] ?? 0, c.align ?? 'left'))
|
|
72
|
+
.join(' ')
|
|
73
|
+
.trimEnd();
|
|
74
|
+
const header = renderRow(columns.map((c) => c.header));
|
|
75
|
+
const sep = renderRow(columns.map((_, i) => '-'.repeat(widths[i] ?? 0)));
|
|
76
|
+
return [header, sep, ...rows.map(renderRow)].join('\n');
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=jsonapi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonapi.js","sourceRoot":"","sources":["../src/jsonapi.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface AppleMusicEntry {
|
|
2
|
+
territory: string;
|
|
3
|
+
currency: string;
|
|
4
|
+
individualPrice: number;
|
|
5
|
+
}
|
|
6
|
+
export interface AppleMusicIndex {
|
|
7
|
+
snapshot: string;
|
|
8
|
+
anchor: string;
|
|
9
|
+
prices: AppleMusicEntry[];
|
|
10
|
+
}
|
|
11
|
+
export type RoundStrategy = 'nearest' | 'down' | 'up';
|
|
12
|
+
export declare function loadIndex(): AppleMusicIndex;
|
|
13
|
+
export declare function indexAsMap(index: AppleMusicIndex): Map<string, AppleMusicEntry>;
|
|
14
|
+
/**
|
|
15
|
+
* PPP factor for a territory: how many local-currency units of *this market's
|
|
16
|
+
* purchasing power* correspond to one anchor-currency unit. Computed from
|
|
17
|
+
* Apple Music's own pricing — using the company's own market signal as the
|
|
18
|
+
* implied PPP-FX rate, which sidesteps the need for a separate FX feed.
|
|
19
|
+
*/
|
|
20
|
+
export declare function computeFactor(localPrice: number, anchorPrice: number): number;
|
|
21
|
+
export declare function computeTarget(basePriceAnchor: number, factor: number): number;
|
|
22
|
+
/**
|
|
23
|
+
* Apply a sanity floor: never drop below `floorFactor × current local price`.
|
|
24
|
+
* Guards against bad index data accidentally setting near-zero prices.
|
|
25
|
+
*/
|
|
26
|
+
export declare function applyFloor(target: number, currentLocal: number, floorFactor: number): number;
|
|
27
|
+
/**
|
|
28
|
+
* Snap `target` to the nearest valid price-point amount according to the chosen
|
|
29
|
+
* strategy. Returns undefined when no candidate is suitable (e.g. all candidates
|
|
30
|
+
* are above target and strategy is 'down').
|
|
31
|
+
*/
|
|
32
|
+
export declare function snapToTier(target: number, candidates: number[], strategy?: RoundStrategy): number | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Parse a customerPrice string from the ASC API. Strings carry currency-specific
|
|
35
|
+
* decimal places without a separator (e.g. "29.99" or "1490" or "1499.99").
|
|
36
|
+
* We treat them all as JS numbers since each subscription is single-currency.
|
|
37
|
+
*/
|
|
38
|
+
export declare function parseDecimal(value: string | number | undefined): number | undefined;
|
|
39
|
+
export declare function percentChange(from: number, to: number): number;
|
|
40
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ppp/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,eAAe,EAAE,CAAC;CAC3B;AAED,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAAC;AAEtD,wBAAgB,SAAS,IAAI,eAAe,CAK3C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAE/E;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAG7E;AAED,wBAAgB,aAAa,CAAC,eAAe,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAG5F;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAAE,EACpB,QAAQ,GAAE,aAAyB,GAClC,MAAM,GAAG,SAAS,CA4BpB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAInF;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAG9D"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import indexData from '../../data/apple-music-prices.json' with { type: 'json' };
|
|
2
|
+
export function loadIndex() {
|
|
3
|
+
const { snapshot, anchor, prices } = indexData;
|
|
4
|
+
return { snapshot, anchor, prices };
|
|
5
|
+
}
|
|
6
|
+
export function indexAsMap(index) {
|
|
7
|
+
return new Map(index.prices.map((p) => [p.territory, p]));
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* PPP factor for a territory: how many local-currency units of *this market's
|
|
11
|
+
* purchasing power* correspond to one anchor-currency unit. Computed from
|
|
12
|
+
* Apple Music's own pricing — using the company's own market signal as the
|
|
13
|
+
* implied PPP-FX rate, which sidesteps the need for a separate FX feed.
|
|
14
|
+
*/
|
|
15
|
+
export function computeFactor(localPrice, anchorPrice) {
|
|
16
|
+
if (anchorPrice === 0)
|
|
17
|
+
throw new Error('Anchor price cannot be zero.');
|
|
18
|
+
return localPrice / anchorPrice;
|
|
19
|
+
}
|
|
20
|
+
export function computeTarget(basePriceAnchor, factor) {
|
|
21
|
+
return basePriceAnchor * factor;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Apply a sanity floor: never drop below `floorFactor × current local price`.
|
|
25
|
+
* Guards against bad index data accidentally setting near-zero prices.
|
|
26
|
+
*/
|
|
27
|
+
export function applyFloor(target, currentLocal, floorFactor) {
|
|
28
|
+
const floor = currentLocal * floorFactor;
|
|
29
|
+
return target < floor ? floor : target;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Snap `target` to the nearest valid price-point amount according to the chosen
|
|
33
|
+
* strategy. Returns undefined when no candidate is suitable (e.g. all candidates
|
|
34
|
+
* are above target and strategy is 'down').
|
|
35
|
+
*/
|
|
36
|
+
export function snapToTier(target, candidates, strategy = 'nearest') {
|
|
37
|
+
if (candidates.length === 0)
|
|
38
|
+
return undefined;
|
|
39
|
+
const sorted = [...candidates].sort((a, b) => a - b);
|
|
40
|
+
if (strategy === 'down') {
|
|
41
|
+
let pick;
|
|
42
|
+
for (const c of sorted) {
|
|
43
|
+
if (c <= target)
|
|
44
|
+
pick = c;
|
|
45
|
+
else
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
return pick ?? sorted[0];
|
|
49
|
+
}
|
|
50
|
+
if (strategy === 'up') {
|
|
51
|
+
for (const c of sorted) {
|
|
52
|
+
if (c >= target)
|
|
53
|
+
return c;
|
|
54
|
+
}
|
|
55
|
+
return sorted[sorted.length - 1];
|
|
56
|
+
}
|
|
57
|
+
// nearest — ties resolve toward the lower candidate (more conservative).
|
|
58
|
+
let best;
|
|
59
|
+
let bestDist = Number.POSITIVE_INFINITY;
|
|
60
|
+
for (const c of sorted) {
|
|
61
|
+
const d = Math.abs(c - target);
|
|
62
|
+
if (d < bestDist || (d === bestDist && c < (best ?? Number.POSITIVE_INFINITY))) {
|
|
63
|
+
best = c;
|
|
64
|
+
bestDist = d;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return best;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Parse a customerPrice string from the ASC API. Strings carry currency-specific
|
|
71
|
+
* decimal places without a separator (e.g. "29.99" or "1490" or "1499.99").
|
|
72
|
+
* We treat them all as JS numbers since each subscription is single-currency.
|
|
73
|
+
*/
|
|
74
|
+
export function parseDecimal(value) {
|
|
75
|
+
if (value === undefined || value === null || value === '')
|
|
76
|
+
return undefined;
|
|
77
|
+
const n = typeof value === 'number' ? value : Number(value);
|
|
78
|
+
return Number.isFinite(n) ? n : undefined;
|
|
79
|
+
}
|
|
80
|
+
export function percentChange(from, to) {
|
|
81
|
+
if (from === 0)
|
|
82
|
+
return 0;
|
|
83
|
+
return ((to - from) / from) * 100;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ppp/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const BundleIdSchema: z.ZodString;
|
|
3
|
+
export declare const AppIdSchema: z.ZodString;
|
|
4
|
+
export declare const SubscriptionGroupIdSchema: z.ZodString;
|
|
5
|
+
export declare const SubscriptionIdSchema: z.ZodString;
|
|
6
|
+
export declare const TerritoryIdSchema: z.ZodString;
|
|
7
|
+
export declare const PricePointIdSchema: z.ZodString;
|
|
8
|
+
export declare const SubscriptionPriceIdSchema: z.ZodString;
|
|
9
|
+
export declare const StartDateSchema: z.ZodString;
|
|
10
|
+
//# sourceMappingURL=schemas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,cAAc,aAGoC,CAAC;AAEhE,eAAO,MAAM,WAAW,aAG+C,CAAC;AAExE,eAAO,MAAM,yBAAyB,aAG2B,CAAC;AAElE,eAAO,MAAM,oBAAoB,aAGqB,CAAC;AAEvD,eAAO,MAAM,iBAAiB,aAGmC,CAAC;AAElE,eAAO,MAAM,kBAAkB,aAGoD,CAAC;AAEpF,eAAO,MAAM,yBAAyB,aAGgC,CAAC;AAEvE,eAAO,MAAM,eAAe,aAKzB,CAAC"}
|
package/dist/schemas.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const BundleIdSchema = z
|
|
3
|
+
.string()
|
|
4
|
+
.min(1)
|
|
5
|
+
.describe('App bundle identifier (e.g., com.example.MyApp).');
|
|
6
|
+
export const AppIdSchema = z
|
|
7
|
+
.string()
|
|
8
|
+
.min(1)
|
|
9
|
+
.describe('App Store Connect app ID (numeric string from /v1/apps).');
|
|
10
|
+
export const SubscriptionGroupIdSchema = z
|
|
11
|
+
.string()
|
|
12
|
+
.min(1)
|
|
13
|
+
.describe('Subscription group ID from /v1/subscriptionGroups.');
|
|
14
|
+
export const SubscriptionIdSchema = z
|
|
15
|
+
.string()
|
|
16
|
+
.min(1)
|
|
17
|
+
.describe('Subscription ID from /v1/subscriptions.');
|
|
18
|
+
export const TerritoryIdSchema = z
|
|
19
|
+
.string()
|
|
20
|
+
.length(3)
|
|
21
|
+
.describe('3-letter ISO territory code (e.g., USA, BRA, JPN).');
|
|
22
|
+
export const PricePointIdSchema = z
|
|
23
|
+
.string()
|
|
24
|
+
.min(1)
|
|
25
|
+
.describe('Subscription price-point ID from /v1/subscriptions/{id}/pricePoints.');
|
|
26
|
+
export const SubscriptionPriceIdSchema = z
|
|
27
|
+
.string()
|
|
28
|
+
.min(1)
|
|
29
|
+
.describe('Subscription price ID (an entry in the price schedule).');
|
|
30
|
+
export const StartDateSchema = z
|
|
31
|
+
.string()
|
|
32
|
+
.regex(/^\d{4}-\d{2}-\d{2}$/, 'Must be YYYY-MM-DD')
|
|
33
|
+
.describe('Date the price change takes effect, YYYY-MM-DD. Apple requires it to be at least 24h in the future; ≥7 days recommended.');
|
|
34
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC;KAC5B,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,CAAC;KACN,QAAQ,CAAC,kDAAkD,CAAC,CAAC;AAEhE,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC;KACzB,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,CAAC;KACN,QAAQ,CAAC,0DAA0D,CAAC,CAAC;AAExE,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC;KACvC,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,CAAC;KACN,QAAQ,CAAC,oDAAoD,CAAC,CAAC;AAElE,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC;KAClC,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,CAAC;KACN,QAAQ,CAAC,yCAAyC,CAAC,CAAC;AAEvD,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC;KAC/B,MAAM,EAAE;KACR,MAAM,CAAC,CAAC,CAAC;KACT,QAAQ,CAAC,oDAAoD,CAAC,CAAC;AAElE,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC;KAChC,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,CAAC;KACN,QAAQ,CAAC,sEAAsE,CAAC,CAAC;AAEpF,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC;KACvC,MAAM,EAAE;KACR,GAAG,CAAC,CAAC,CAAC;KACN,QAAQ,CAAC,yDAAyD,CAAC,CAAC;AAEvE,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC;KAC7B,MAAM,EAAE;KACR,KAAK,CAAC,qBAAqB,EAAE,oBAAoB,CAAC;KAClD,QAAQ,CACP,0HAA0H,CAC3H,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@akoskomuves/appstoreconnect-mcp",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Model Context Protocol server for the Apple App Store Connect API.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"appstoreconnect-mcp": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"data",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE",
|
|
16
|
+
"CHANGELOG.md"
|
|
17
|
+
],
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc -p tsconfig.build.json && chmod +x dist/index.js",
|
|
20
|
+
"dev": "tsx watch src/index.ts",
|
|
21
|
+
"start": "node dist/index.js",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"lint": "biome check .",
|
|
24
|
+
"lint:fix": "biome check --write .",
|
|
25
|
+
"format": "biome format --write .",
|
|
26
|
+
"test": "vitest run",
|
|
27
|
+
"test:watch": "vitest",
|
|
28
|
+
"changeset": "changeset",
|
|
29
|
+
"version": "changeset version",
|
|
30
|
+
"release": "npm run build && changeset publish",
|
|
31
|
+
"prepublishOnly": "npm run build"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"mcp",
|
|
35
|
+
"model-context-protocol",
|
|
36
|
+
"claude",
|
|
37
|
+
"anthropic",
|
|
38
|
+
"app-store-connect",
|
|
39
|
+
"appstoreconnect",
|
|
40
|
+
"appstore",
|
|
41
|
+
"ios",
|
|
42
|
+
"asc",
|
|
43
|
+
"subscription-pricing",
|
|
44
|
+
"ppp"
|
|
45
|
+
],
|
|
46
|
+
"author": {
|
|
47
|
+
"name": "Akos Komuves",
|
|
48
|
+
"email": "komuvesakos@icloud.com",
|
|
49
|
+
"url": "https://github.com/akoskomuves"
|
|
50
|
+
},
|
|
51
|
+
"license": "MIT",
|
|
52
|
+
"repository": {
|
|
53
|
+
"type": "git",
|
|
54
|
+
"url": "git+https://github.com/akoskomuves/appstoreconnect-mcp.git"
|
|
55
|
+
},
|
|
56
|
+
"bugs": {
|
|
57
|
+
"url": "https://github.com/akoskomuves/appstoreconnect-mcp/issues"
|
|
58
|
+
},
|
|
59
|
+
"homepage": "https://github.com/akoskomuves/appstoreconnect-mcp#readme",
|
|
60
|
+
"engines": {
|
|
61
|
+
"node": ">=22"
|
|
62
|
+
},
|
|
63
|
+
"dependencies": {
|
|
64
|
+
"@inquirer/prompts": "^8.4.2",
|
|
65
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
66
|
+
"jose": "^6.2.0",
|
|
67
|
+
"open": "^11.0.0",
|
|
68
|
+
"zod": "^4.0.0"
|
|
69
|
+
},
|
|
70
|
+
"devDependencies": {
|
|
71
|
+
"@biomejs/biome": "^2.0.0",
|
|
72
|
+
"@changesets/cli": "^2.27.0",
|
|
73
|
+
"@types/node": "^22.10.0",
|
|
74
|
+
"@vitest/coverage-v8": "^4.1.5",
|
|
75
|
+
"tsx": "^4.19.0",
|
|
76
|
+
"typescript": "^5.7.0",
|
|
77
|
+
"vitest": "^4.1.5"
|
|
78
|
+
}
|
|
79
|
+
}
|