@onmyway133/asc-cli 1.0.2 → 1.0.3
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/README.md +12 -80
- package/dist/index.js +164 -156
- package/docs/DEVELOPMENT.md +112 -0
- package/package.json +1 -1
- package/src/commands/app-info.ts +32 -34
- package/src/commands/apps.ts +17 -14
- package/src/commands/availability.ts +17 -16
- package/src/commands/beta-review.ts +51 -61
- package/src/commands/builds.ts +37 -29
- package/src/commands/game-center.ts +56 -55
- package/src/commands/iap.ts +47 -53
- package/src/commands/localizations.ts +83 -0
- package/src/commands/metadata.ts +25 -18
- package/src/commands/phased-release.ts +85 -0
- package/src/commands/pricing.ts +34 -30
- package/src/commands/reports.ts +13 -10
- package/src/commands/review-details.ts +79 -0
- package/src/commands/review-submission.ts +143 -0
- package/src/commands/reviews.ts +36 -30
- package/src/commands/screenshots.ts +40 -51
- package/src/commands/signing.ts +80 -100
- package/src/commands/subscriptions.ts +55 -63
- package/src/commands/testflight.ts +34 -23
- package/src/commands/versions.ts +40 -18
- package/src/commands/xcode-cloud.ts +68 -65
- package/src/index.ts +313 -1
package/src/commands/pricing.ts
CHANGED
|
@@ -1,22 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
appsAppPriceScheduleGetToOneRelated,
|
|
3
|
+
appPriceSchedulesCreateInstance,
|
|
4
|
+
appsAppPricePointsGetToManyRelated,
|
|
5
|
+
territoriesGetCollection,
|
|
6
|
+
} from "../api/generated/sdk.gen.ts"
|
|
7
|
+
import { throwOnError } from "../api/client.ts"
|
|
2
8
|
import { detectFormat, formatDate, printJSON, printSuccess, printTable } from "../utils/output.ts"
|
|
3
9
|
|
|
4
10
|
export async function pricingScheduleGet(appId: string, opts: { output?: string } = {}): Promise<void> {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
params: {
|
|
11
|
-
include: "manualPrices,automaticPrices,baseTerritory",
|
|
12
|
-
"fields[territories]": "currency,name",
|
|
11
|
+
const result = await appsAppPriceScheduleGetToOneRelated({
|
|
12
|
+
path: { id: appId },
|
|
13
|
+
query: {
|
|
14
|
+
include: ["manualPrices", "automaticPrices", "baseTerritory"],
|
|
15
|
+
"fields[territories]": ["currency"],
|
|
13
16
|
},
|
|
14
17
|
})
|
|
15
|
-
const body = result
|
|
18
|
+
const body = throwOnError(result)
|
|
16
19
|
const fmt = detectFormat(opts.output)
|
|
17
20
|
if (fmt === "json") { printJSON(body); return }
|
|
18
21
|
console.log(`Schedule ID: ${body.data.id}`)
|
|
19
|
-
const included = body.included ?? []
|
|
22
|
+
const included = (body as { data: unknown; included?: Array<{ type: string; id: string; attributes?: Record<string, unknown> }> }).included ?? []
|
|
20
23
|
const base = included.find(r => r.type === "territories")
|
|
21
24
|
if (base) {
|
|
22
25
|
const attrs = base.attributes as { currency?: string; name?: string } | undefined
|
|
@@ -40,8 +43,7 @@ export async function pricingScheduleSet(opts: {
|
|
|
40
43
|
baseTerritory: string
|
|
41
44
|
pricePointId: string
|
|
42
45
|
}): Promise<void> {
|
|
43
|
-
await
|
|
44
|
-
method: "POST",
|
|
46
|
+
await appPriceSchedulesCreateInstance({
|
|
45
47
|
body: {
|
|
46
48
|
data: {
|
|
47
49
|
type: "appPriceSchedules",
|
|
@@ -60,7 +62,7 @@ export async function pricingScheduleSet(opts: {
|
|
|
60
62
|
appPricePoint: { data: { type: "appPricePoints", id: opts.pricePointId } },
|
|
61
63
|
territory: { data: { type: "territories", id: opts.baseTerritory } },
|
|
62
64
|
},
|
|
63
|
-
},
|
|
65
|
+
} as never,
|
|
64
66
|
],
|
|
65
67
|
},
|
|
66
68
|
})
|
|
@@ -72,39 +74,41 @@ export async function pricingPointsList(opts: {
|
|
|
72
74
|
territory?: string
|
|
73
75
|
output?: string
|
|
74
76
|
}): Promise<void> {
|
|
75
|
-
const
|
|
76
|
-
"fields[appPricePoints]": "customerPrice,proceeds,territory",
|
|
77
|
-
limit:
|
|
77
|
+
const query: Record<string, unknown> = {
|
|
78
|
+
"fields[appPricePoints]": ["customerPrice", "proceeds", "territory"],
|
|
79
|
+
limit: 200,
|
|
78
80
|
}
|
|
79
|
-
if (opts.territory)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
if (opts.territory) query["filter[territory]"] = [opts.territory]
|
|
82
|
+
|
|
83
|
+
const result = await appsAppPricePointsGetToManyRelated({
|
|
84
|
+
path: { id: opts.appId },
|
|
85
|
+
query: query as never,
|
|
86
|
+
})
|
|
87
|
+
const data = throwOnError(result)
|
|
88
|
+
const items = data.data
|
|
84
89
|
const fmt = detectFormat(opts.output)
|
|
85
90
|
if (fmt === "json") { printJSON(items); return }
|
|
86
91
|
printTable(
|
|
87
92
|
["ID", "Customer Price", "Proceeds", "Territory"],
|
|
88
93
|
items.map(p => [
|
|
89
94
|
p.id,
|
|
90
|
-
p.attributes
|
|
91
|
-
p.attributes
|
|
92
|
-
String(p.attributes
|
|
95
|
+
(p.attributes as Record<string, unknown>)?.customerPrice as string ?? "-",
|
|
96
|
+
(p.attributes as Record<string, unknown>)?.proceeds as string ?? "-",
|
|
97
|
+
String((p.attributes as Record<string, unknown>)?.territory ?? "-"),
|
|
93
98
|
]),
|
|
94
99
|
`Price Points (${items.length})`,
|
|
95
100
|
)
|
|
96
101
|
}
|
|
97
102
|
|
|
98
103
|
export async function territoriesList(opts: { output?: string } = {}): Promise<void> {
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}>("/v1/territories")
|
|
104
|
+
const result = await territoriesGetCollection()
|
|
105
|
+
const data = throwOnError(result)
|
|
106
|
+
const items = data.data
|
|
103
107
|
const fmt = detectFormat(opts.output)
|
|
104
108
|
if (fmt === "json") { printJSON(items); return }
|
|
105
109
|
printTable(
|
|
106
110
|
["Territory Code", "Name", "Currency"],
|
|
107
|
-
items.map(t => [t.id, t.attributes
|
|
111
|
+
items.map(t => [t.id, (t.attributes as { currency?: string })?.currency ?? "-", ""]),
|
|
108
112
|
`Territories (${items.length})`,
|
|
109
113
|
)
|
|
110
114
|
}
|
package/src/commands/reports.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
appsAnalyticsReportRequestsGetToManyRelated,
|
|
3
|
+
analyticsReportRequestsCreateInstance,
|
|
4
|
+
} from "../api/generated/sdk.gen.ts"
|
|
5
|
+
import { throwOnError } from "../api/client.ts"
|
|
2
6
|
import { detectFormat, formatDate, printJSON, printTable } from "../utils/output.ts"
|
|
3
7
|
|
|
4
8
|
// ---- Sales and Finance Reports ----
|
|
@@ -84,15 +88,14 @@ export async function analyticsReportsList(opts: {
|
|
|
84
88
|
appId: string
|
|
85
89
|
output?: string
|
|
86
90
|
}): Promise<void> {
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}>(`/v1/apps/${opts.appId}/analyticsReportRequests`)
|
|
91
|
+
const result = await appsAnalyticsReportRequestsGetToManyRelated({ path: { id: opts.appId } })
|
|
92
|
+
const data = throwOnError(result)
|
|
93
|
+
const items = data.data
|
|
91
94
|
const fmt = detectFormat(opts.output)
|
|
92
95
|
if (fmt === "json") { printJSON(items); return }
|
|
93
96
|
printTable(
|
|
94
97
|
["Request ID", "State"],
|
|
95
|
-
items.map(r => [r.id, String(r.attributes
|
|
98
|
+
items.map(r => [r.id, String(r.attributes?.accessType ?? r.id)]),
|
|
96
99
|
`Analytics Report Requests (${items.length})`,
|
|
97
100
|
)
|
|
98
101
|
}
|
|
@@ -101,16 +104,16 @@ export async function analyticsReportRequest(opts: {
|
|
|
101
104
|
appId: string
|
|
102
105
|
category: string
|
|
103
106
|
}): Promise<void> {
|
|
104
|
-
const result = await
|
|
105
|
-
method: "POST",
|
|
107
|
+
const result = await analyticsReportRequestsCreateInstance({
|
|
106
108
|
body: {
|
|
107
109
|
data: {
|
|
108
110
|
type: "analyticsReportRequests",
|
|
109
|
-
attributes: { accessType: opts.category },
|
|
111
|
+
attributes: { accessType: opts.category as never },
|
|
110
112
|
relationships: { app: { data: { type: "apps", id: opts.appId } } },
|
|
111
113
|
},
|
|
112
114
|
},
|
|
113
115
|
})
|
|
114
|
-
|
|
116
|
+
const data = throwOnError(result)
|
|
117
|
+
console.log(`Analytics report request created: ${data.data.id}`)
|
|
115
118
|
console.log("Check back later with: asc reports analytics-list --app-id <id>")
|
|
116
119
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {
|
|
2
|
+
appStoreVersionsAppStoreReviewDetailGetToOneRelated,
|
|
3
|
+
appStoreReviewDetailsCreateInstance,
|
|
4
|
+
appStoreReviewDetailsUpdateInstance,
|
|
5
|
+
} from "../api/generated/sdk.gen.ts"
|
|
6
|
+
import { throwOnError, ASCError } from "../api/client.ts"
|
|
7
|
+
import { detectFormat, printJSON, printSuccess } from "../utils/output.ts"
|
|
8
|
+
|
|
9
|
+
export async function reviewDetailsGet(versionId: string, output?: string): Promise<void> {
|
|
10
|
+
const result = await appStoreVersionsAppStoreReviewDetailGetToOneRelated({ path: { id: versionId } })
|
|
11
|
+
const data = throwOnError(result)
|
|
12
|
+
const d = data.data
|
|
13
|
+
|
|
14
|
+
const fmt = detectFormat(output)
|
|
15
|
+
if (fmt === "json") { printJSON({ id: d.id, ...d.attributes }); return }
|
|
16
|
+
console.log(`ID: ${d.id}`)
|
|
17
|
+
console.log(`Contact: ${[d.attributes?.contactFirstName, d.attributes?.contactLastName].filter(Boolean).join(" ") || "-"}`)
|
|
18
|
+
console.log(`Contact Email: ${d.attributes?.contactEmail ?? "-"}`)
|
|
19
|
+
console.log(`Contact Phone: ${d.attributes?.contactPhone ?? "-"}`)
|
|
20
|
+
console.log(`Demo Account: ${d.attributes?.demoAccountName ?? "-"}`)
|
|
21
|
+
console.log(`Demo Account Required:${d.attributes?.demoAccountRequired ? " yes" : " no"}`)
|
|
22
|
+
console.log(`Notes: ${d.attributes?.notes ?? "-"}`)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function reviewDetailsUpdate(opts: {
|
|
26
|
+
versionId: string
|
|
27
|
+
contactFirstName?: string
|
|
28
|
+
contactLastName?: string
|
|
29
|
+
contactEmail?: string
|
|
30
|
+
contactPhone?: string
|
|
31
|
+
demoAccountName?: string
|
|
32
|
+
demoAccountPassword?: string
|
|
33
|
+
demoAccountRequired?: boolean
|
|
34
|
+
notes?: string
|
|
35
|
+
}): Promise<void> {
|
|
36
|
+
// Try to get existing review detail ID
|
|
37
|
+
let existingId: string | undefined
|
|
38
|
+
try {
|
|
39
|
+
const existing = await appStoreVersionsAppStoreReviewDetailGetToOneRelated({ path: { id: opts.versionId } })
|
|
40
|
+
const data = throwOnError(existing)
|
|
41
|
+
existingId = data.data.id
|
|
42
|
+
} catch (err) {
|
|
43
|
+
if (!(err instanceof ASCError) || err.status !== 404) throw err
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const attributes = {
|
|
47
|
+
contactFirstName: opts.contactFirstName,
|
|
48
|
+
contactLastName: opts.contactLastName,
|
|
49
|
+
contactEmail: opts.contactEmail,
|
|
50
|
+
contactPhone: opts.contactPhone,
|
|
51
|
+
demoAccountName: opts.demoAccountName,
|
|
52
|
+
demoAccountPassword: opts.demoAccountPassword,
|
|
53
|
+
demoAccountRequired: opts.demoAccountRequired,
|
|
54
|
+
notes: opts.notes,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (existingId) {
|
|
58
|
+
const result = await appStoreReviewDetailsUpdateInstance({
|
|
59
|
+
path: { id: existingId },
|
|
60
|
+
body: { data: { type: "appStoreReviewDetails", id: existingId, attributes } },
|
|
61
|
+
})
|
|
62
|
+
throwOnError(result)
|
|
63
|
+
printSuccess("Review details updated")
|
|
64
|
+
} else {
|
|
65
|
+
const result = await appStoreReviewDetailsCreateInstance({
|
|
66
|
+
body: {
|
|
67
|
+
data: {
|
|
68
|
+
type: "appStoreReviewDetails",
|
|
69
|
+
attributes,
|
|
70
|
+
relationships: {
|
|
71
|
+
appStoreVersion: { data: { type: "appStoreVersions", id: opts.versionId } },
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
})
|
|
76
|
+
throwOnError(result)
|
|
77
|
+
printSuccess("Review details created")
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import {
|
|
2
|
+
reviewSubmissionsGetCollection,
|
|
3
|
+
reviewSubmissionsCreateInstance,
|
|
4
|
+
reviewSubmissionsGetInstance,
|
|
5
|
+
reviewSubmissionsUpdateInstance,
|
|
6
|
+
reviewSubmissionsItemsGetToManyRelated,
|
|
7
|
+
reviewSubmissionItemsCreateInstance,
|
|
8
|
+
reviewSubmissionItemsDeleteInstance,
|
|
9
|
+
} from "../api/generated/sdk.gen.ts"
|
|
10
|
+
import { throwOnError } from "../api/client.ts"
|
|
11
|
+
import { detectFormat, formatDate, printJSON, printSuccess, printTable } from "../utils/output.ts"
|
|
12
|
+
|
|
13
|
+
export async function reviewSubmissionList(opts: {
|
|
14
|
+
appId: string
|
|
15
|
+
output?: string
|
|
16
|
+
}): Promise<void> {
|
|
17
|
+
const result = await reviewSubmissionsGetCollection({
|
|
18
|
+
query: { "filter[app]": [opts.appId] },
|
|
19
|
+
})
|
|
20
|
+
const data = throwOnError(result)
|
|
21
|
+
const items = data.data
|
|
22
|
+
|
|
23
|
+
const fmt = detectFormat(opts.output)
|
|
24
|
+
if (fmt === "json") { printJSON(items.map(s => ({ id: s.id, ...s.attributes }))); return }
|
|
25
|
+
printTable(
|
|
26
|
+
["ID", "Platform", "State", "Date"],
|
|
27
|
+
items.map(s => [
|
|
28
|
+
s.id,
|
|
29
|
+
s.attributes?.platform ?? "-",
|
|
30
|
+
s.attributes?.state ?? "-",
|
|
31
|
+
formatDate(s.attributes?.submittedDate),
|
|
32
|
+
]),
|
|
33
|
+
`Review Submissions (${items.length})`,
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function reviewSubmissionCreate(opts: {
|
|
38
|
+
appId: string
|
|
39
|
+
platform?: string
|
|
40
|
+
}): Promise<void> {
|
|
41
|
+
const platform = (opts.platform ?? "IOS").toUpperCase() as "IOS" | "MAC_OS" | "TV_OS" | "VISION_OS"
|
|
42
|
+
const result = await reviewSubmissionsCreateInstance({
|
|
43
|
+
body: {
|
|
44
|
+
data: {
|
|
45
|
+
type: "reviewSubmissions",
|
|
46
|
+
attributes: { platform },
|
|
47
|
+
relationships: {
|
|
48
|
+
app: { data: { type: "apps", id: opts.appId } },
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
})
|
|
53
|
+
const data = throwOnError(result)
|
|
54
|
+
const s = data.data
|
|
55
|
+
printSuccess(`Review submission created — ID: ${s.id}`)
|
|
56
|
+
console.log(` State: ${s.attributes?.state ?? "-"}`)
|
|
57
|
+
console.log(` Platform: ${platform}`)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function reviewSubmissionGet(submissionId: string, output?: string): Promise<void> {
|
|
61
|
+
const result = await reviewSubmissionsGetInstance({ path: { id: submissionId } })
|
|
62
|
+
const data = throwOnError(result)
|
|
63
|
+
const s = data.data
|
|
64
|
+
|
|
65
|
+
const fmt = detectFormat(output)
|
|
66
|
+
if (fmt === "json") { printJSON({ id: s.id, ...s.attributes }); return }
|
|
67
|
+
console.log(`ID: ${s.id}`)
|
|
68
|
+
console.log(`Platform: ${s.attributes?.platform ?? "-"}`)
|
|
69
|
+
console.log(`State: ${s.attributes?.state ?? "-"}`)
|
|
70
|
+
console.log(`Date: ${formatDate(s.attributes?.submittedDate)}`)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function reviewSubmissionSubmit(submissionId: string): Promise<void> {
|
|
74
|
+
const result = await reviewSubmissionsUpdateInstance({
|
|
75
|
+
path: { id: submissionId },
|
|
76
|
+
body: {
|
|
77
|
+
data: {
|
|
78
|
+
type: "reviewSubmissions",
|
|
79
|
+
id: submissionId,
|
|
80
|
+
attributes: { submitted: true },
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
})
|
|
84
|
+
throwOnError(result)
|
|
85
|
+
printSuccess(`Submission ${submissionId} submitted for review`)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export async function reviewSubmissionCancel(submissionId: string): Promise<void> {
|
|
89
|
+
const result = await reviewSubmissionsUpdateInstance({
|
|
90
|
+
path: { id: submissionId },
|
|
91
|
+
body: {
|
|
92
|
+
data: {
|
|
93
|
+
type: "reviewSubmissions",
|
|
94
|
+
id: submissionId,
|
|
95
|
+
attributes: { canceled: true },
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
})
|
|
99
|
+
throwOnError(result)
|
|
100
|
+
printSuccess(`Submission ${submissionId} cancelled`)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export async function reviewSubmissionItemsList(opts: {
|
|
104
|
+
submissionId: string
|
|
105
|
+
output?: string
|
|
106
|
+
}): Promise<void> {
|
|
107
|
+
const result = await reviewSubmissionsItemsGetToManyRelated({ path: { id: opts.submissionId } })
|
|
108
|
+
const data = throwOnError(result)
|
|
109
|
+
const items = data.data
|
|
110
|
+
|
|
111
|
+
const fmt = detectFormat(opts.output)
|
|
112
|
+
if (fmt === "json") { printJSON(items.map(i => ({ id: i.id, ...i.attributes }))); return }
|
|
113
|
+
printTable(
|
|
114
|
+
["Item ID", "State"],
|
|
115
|
+
items.map(i => [i.id, i.attributes?.state ?? "-"]),
|
|
116
|
+
`Submission Items (${items.length})`,
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export async function reviewSubmissionItemAdd(opts: {
|
|
121
|
+
submissionId: string
|
|
122
|
+
appStoreVersionId: string
|
|
123
|
+
}): Promise<void> {
|
|
124
|
+
const result = await reviewSubmissionItemsCreateInstance({
|
|
125
|
+
body: {
|
|
126
|
+
data: {
|
|
127
|
+
type: "reviewSubmissionItems",
|
|
128
|
+
relationships: {
|
|
129
|
+
reviewSubmission: { data: { type: "reviewSubmissions", id: opts.submissionId } },
|
|
130
|
+
appStoreVersion: { data: { type: "appStoreVersions", id: opts.appStoreVersionId } },
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
})
|
|
135
|
+
const data = throwOnError(result)
|
|
136
|
+
printSuccess(`Item added — ID: ${data.data.id}`)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export async function reviewSubmissionItemDelete(itemId: string): Promise<void> {
|
|
140
|
+
const result = await reviewSubmissionItemsDeleteInstance({ path: { id: itemId } })
|
|
141
|
+
throwOnError(result)
|
|
142
|
+
printSuccess(`Submission item ${itemId} removed`)
|
|
143
|
+
}
|
package/src/commands/reviews.ts
CHANGED
|
@@ -1,20 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
appsCustomerReviewsGetToManyRelated,
|
|
3
|
+
customerReviewsGetInstance,
|
|
4
|
+
customerReviewsResponseGetToOneRelated,
|
|
5
|
+
customerReviewResponsesCreateInstance,
|
|
6
|
+
customerReviewResponsesDeleteInstance,
|
|
7
|
+
} from "../api/generated/sdk.gen.ts"
|
|
8
|
+
import { throwOnError, ascFetch } from "../api/client.ts"
|
|
3
9
|
import { detectFormat, formatDate, printJSON, printSuccess, printTable, truncate } from "../utils/output.ts"
|
|
4
10
|
|
|
5
11
|
export async function reviewsList(opts: {
|
|
6
12
|
appId: string
|
|
7
13
|
output?: string
|
|
8
14
|
}): Promise<void> {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
{
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"sort": "-createdDate",
|
|
15
|
-
},
|
|
15
|
+
const result = await appsCustomerReviewsGetToManyRelated({
|
|
16
|
+
path: { id: opts.appId },
|
|
17
|
+
query: {
|
|
18
|
+
"fields[customerReviews]": ["rating", "title", "body", "reviewerNickname", "createdDate", "territory"],
|
|
19
|
+
sort: ["-createdDate"],
|
|
16
20
|
},
|
|
17
|
-
)
|
|
21
|
+
})
|
|
22
|
+
const data = throwOnError(result)
|
|
23
|
+
const reviews = data.data
|
|
18
24
|
|
|
19
25
|
const fmt = detectFormat(opts.output)
|
|
20
26
|
if (fmt === "json") {
|
|
@@ -26,18 +32,19 @@ export async function reviewsList(opts: {
|
|
|
26
32
|
["ID", "Rating", "Title", "Body", "Date"],
|
|
27
33
|
reviews.map((r) => [
|
|
28
34
|
r.id,
|
|
29
|
-
"★".repeat(r.attributes
|
|
30
|
-
truncate(r.attributes
|
|
31
|
-
truncate(r.attributes
|
|
32
|
-
formatDate(r.attributes
|
|
35
|
+
"★".repeat(r.attributes?.rating ?? 0) + "☆".repeat(5 - (r.attributes?.rating ?? 0)),
|
|
36
|
+
truncate(r.attributes?.title ?? "-", 30),
|
|
37
|
+
truncate(r.attributes?.body ?? "-", 50),
|
|
38
|
+
formatDate(r.attributes?.createdDate ?? ""),
|
|
33
39
|
]),
|
|
34
40
|
`Reviews (${reviews.length})`,
|
|
35
41
|
)
|
|
36
42
|
}
|
|
37
43
|
|
|
38
44
|
export async function reviewsGet(reviewId: string, opts: { output?: string } = {}): Promise<void> {
|
|
39
|
-
const
|
|
40
|
-
const
|
|
45
|
+
const result = await customerReviewsGetInstance({ path: { id: reviewId } })
|
|
46
|
+
const data = throwOnError(result)
|
|
47
|
+
const r = data.data
|
|
41
48
|
|
|
42
49
|
const fmt = detectFormat(opts.output)
|
|
43
50
|
if (fmt === "json") {
|
|
@@ -46,12 +53,12 @@ export async function reviewsGet(reviewId: string, opts: { output?: string } = {
|
|
|
46
53
|
}
|
|
47
54
|
|
|
48
55
|
console.log(`ID: ${r.id}`)
|
|
49
|
-
console.log(`Rating: ${"★".repeat(r.attributes
|
|
50
|
-
console.log(`Title: ${r.attributes
|
|
51
|
-
console.log(`Body: ${r.attributes
|
|
52
|
-
console.log(`Author: ${r.attributes
|
|
53
|
-
console.log(`Date: ${formatDate(r.attributes
|
|
54
|
-
console.log(`Territory:${r.attributes
|
|
56
|
+
console.log(`Rating: ${"★".repeat(r.attributes?.rating ?? 0)}${"☆".repeat(5 - (r.attributes?.rating ?? 0))}`)
|
|
57
|
+
console.log(`Title: ${r.attributes?.title ?? "-"}`)
|
|
58
|
+
console.log(`Body: ${r.attributes?.body ?? "-"}`)
|
|
59
|
+
console.log(`Author: ${r.attributes?.reviewerNickname ?? "-"}`)
|
|
60
|
+
console.log(`Date: ${formatDate(r.attributes?.createdDate ?? "")}`)
|
|
61
|
+
console.log(`Territory:${r.attributes?.territory ?? "-"}`)
|
|
55
62
|
}
|
|
56
63
|
|
|
57
64
|
export async function reviewsRespond(opts: {
|
|
@@ -59,25 +66,24 @@ export async function reviewsRespond(opts: {
|
|
|
59
66
|
message: string
|
|
60
67
|
}): Promise<void> {
|
|
61
68
|
// Check if a response already exists
|
|
62
|
-
const existingRes = await
|
|
63
|
-
|
|
64
|
-
).catch(() => null)
|
|
69
|
+
const existingRes = await customerReviewsResponseGetToOneRelated({ path: { id: opts.reviewId } }).catch(() => null)
|
|
70
|
+
const existingData = existingRes ? throwOnError(existingRes) : null
|
|
65
71
|
|
|
66
|
-
if (
|
|
67
|
-
|
|
72
|
+
if (existingData?.data) {
|
|
73
|
+
// No SDK update function for customerReviewResponses — use ascFetch for PATCH
|
|
74
|
+
await ascFetch(`/v1/customerReviewResponses/${existingData.data.id}`, {
|
|
68
75
|
method: "PATCH",
|
|
69
76
|
body: {
|
|
70
77
|
data: {
|
|
71
78
|
type: "customerReviewResponses",
|
|
72
|
-
id:
|
|
79
|
+
id: existingData.data.id,
|
|
73
80
|
attributes: { responseBody: opts.message },
|
|
74
81
|
},
|
|
75
82
|
},
|
|
76
83
|
})
|
|
77
84
|
printSuccess("Review response updated")
|
|
78
85
|
} else {
|
|
79
|
-
await
|
|
80
|
-
method: "POST",
|
|
86
|
+
await customerReviewResponsesCreateInstance({
|
|
81
87
|
body: {
|
|
82
88
|
data: {
|
|
83
89
|
type: "customerReviewResponses",
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
appStoreVersionLocalizationsAppScreenshotSetsGetToManyRelated,
|
|
3
|
+
appScreenshotSetsAppScreenshotsGetToManyRelated,
|
|
4
|
+
appScreenshotsCreateInstance,
|
|
5
|
+
appScreenshotsUpdateInstance,
|
|
6
|
+
appScreenshotsDeleteInstance,
|
|
7
|
+
appStoreVersionLocalizationsAppPreviewSetsGetToManyRelated,
|
|
8
|
+
} from "../api/generated/sdk.gen.ts"
|
|
9
|
+
import { throwOnError } from "../api/client.ts"
|
|
2
10
|
import { readFileSync } from "fs"
|
|
3
11
|
import { detectFormat, printJSON, printSuccess, printTable } from "../utils/output.ts"
|
|
4
12
|
|
|
@@ -8,20 +16,17 @@ export async function screenshotSetsList(opts: {
|
|
|
8
16
|
versionLocalizationId: string
|
|
9
17
|
output?: string
|
|
10
18
|
}): Promise<void> {
|
|
11
|
-
const
|
|
12
|
-
id:
|
|
13
|
-
|
|
14
|
-
screenshotDisplayType?: string
|
|
15
|
-
appScreenshots?: { meta?: { total?: number } }
|
|
16
|
-
}
|
|
17
|
-
}>(`/v1/appStoreVersionLocalizations/${opts.versionLocalizationId}/appScreenshotSets`, {
|
|
18
|
-
params: { "fields[appScreenshotSets]": "screenshotDisplayType,appScreenshots" },
|
|
19
|
+
const result = await appStoreVersionLocalizationsAppScreenshotSetsGetToManyRelated({
|
|
20
|
+
path: { id: opts.versionLocalizationId },
|
|
21
|
+
query: { "fields[appScreenshotSets]": ["screenshotDisplayType", "appScreenshots"] },
|
|
19
22
|
})
|
|
23
|
+
const data = throwOnError(result)
|
|
24
|
+
const items = data.data
|
|
20
25
|
const fmt = detectFormat(opts.output)
|
|
21
26
|
if (fmt === "json") { printJSON(items); return }
|
|
22
27
|
printTable(
|
|
23
28
|
["Set ID", "Display Type"],
|
|
24
|
-
items.map(s => [s.id, s.attributes
|
|
29
|
+
items.map(s => [s.id, s.attributes?.screenshotDisplayType ?? "-"]),
|
|
25
30
|
`Screenshot Sets (${items.length})`,
|
|
26
31
|
)
|
|
27
32
|
}
|
|
@@ -30,24 +35,19 @@ export async function screenshotsList(opts: {
|
|
|
30
35
|
setId: string
|
|
31
36
|
output?: string
|
|
32
37
|
}): Promise<void> {
|
|
33
|
-
const
|
|
34
|
-
id:
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
sourceFileChecksum?: string
|
|
39
|
-
assetDeliveryState?: { state?: string }
|
|
40
|
-
imageAsset?: { templateUrl?: string; width?: number; height?: number }
|
|
41
|
-
}
|
|
42
|
-
}>(`/v1/appScreenshotSets/${opts.setId}/appScreenshots`)
|
|
38
|
+
const result = await appScreenshotSetsAppScreenshotsGetToManyRelated({
|
|
39
|
+
path: { id: opts.setId },
|
|
40
|
+
})
|
|
41
|
+
const data = throwOnError(result)
|
|
42
|
+
const items = data.data
|
|
43
43
|
const fmt = detectFormat(opts.output)
|
|
44
44
|
if (fmt === "json") { printJSON(items); return }
|
|
45
45
|
printTable(
|
|
46
46
|
["ID", "File Name", "State"],
|
|
47
47
|
items.map(s => [
|
|
48
48
|
s.id,
|
|
49
|
-
s.attributes
|
|
50
|
-
s.attributes
|
|
49
|
+
s.attributes?.fileName ?? "-",
|
|
50
|
+
s.attributes?.assetDeliveryState?.state ?? "-",
|
|
51
51
|
]),
|
|
52
52
|
`Screenshots (${items.length})`,
|
|
53
53
|
)
|
|
@@ -62,21 +62,7 @@ export async function screenshotCreate(opts: {
|
|
|
62
62
|
const fileSize = fileData.length
|
|
63
63
|
|
|
64
64
|
// Step 1: Reserve asset
|
|
65
|
-
const reserve = await
|
|
66
|
-
data: {
|
|
67
|
-
id: string
|
|
68
|
-
attributes: {
|
|
69
|
-
uploadOperations?: Array<{
|
|
70
|
-
url: string
|
|
71
|
-
method: string
|
|
72
|
-
offset: number
|
|
73
|
-
length: number
|
|
74
|
-
requestHeaders?: Array<{ name: string; value: string }>
|
|
75
|
-
}>
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}>("/v1/appScreenshots", {
|
|
79
|
-
method: "POST",
|
|
65
|
+
const reserve = await appScreenshotsCreateInstance({
|
|
80
66
|
body: {
|
|
81
67
|
data: {
|
|
82
68
|
type: "appScreenshots",
|
|
@@ -87,21 +73,23 @@ export async function screenshotCreate(opts: {
|
|
|
87
73
|
},
|
|
88
74
|
},
|
|
89
75
|
})
|
|
90
|
-
|
|
91
|
-
const screenshotId =
|
|
92
|
-
const uploads =
|
|
76
|
+
const reserveData = throwOnError(reserve)
|
|
77
|
+
const screenshotId = reserveData.data.id
|
|
78
|
+
const uploads = reserveData.data.attributes?.uploadOperations ?? []
|
|
93
79
|
|
|
94
80
|
// Step 2: Upload parts
|
|
95
81
|
for (const op of uploads) {
|
|
96
|
-
const chunk = fileData.subarray(op.offset, op.offset + op.length)
|
|
82
|
+
const chunk = fileData.subarray(op.offset ?? 0, (op.offset ?? 0) + (op.length ?? 0))
|
|
97
83
|
const headers: Record<string, string> = { "Content-Type": "image/png" }
|
|
98
|
-
for (const h of op.requestHeaders ?? [])
|
|
99
|
-
|
|
84
|
+
for (const h of op.requestHeaders ?? []) {
|
|
85
|
+
if (h.name && h.value) headers[h.name] = h.value
|
|
86
|
+
}
|
|
87
|
+
await fetch(op.url ?? "", { method: op.method ?? "PUT", headers, body: chunk })
|
|
100
88
|
}
|
|
101
89
|
|
|
102
90
|
// Step 3: Commit
|
|
103
|
-
await
|
|
104
|
-
|
|
91
|
+
await appScreenshotsUpdateInstance({
|
|
92
|
+
path: { id: screenshotId },
|
|
105
93
|
body: {
|
|
106
94
|
data: {
|
|
107
95
|
type: "appScreenshots",
|
|
@@ -115,7 +103,7 @@ export async function screenshotCreate(opts: {
|
|
|
115
103
|
}
|
|
116
104
|
|
|
117
105
|
export async function screenshotDelete(screenshotId: string): Promise<void> {
|
|
118
|
-
await
|
|
106
|
+
await appScreenshotsDeleteInstance({ path: { id: screenshotId } })
|
|
119
107
|
printSuccess(`Screenshot ${screenshotId} deleted`)
|
|
120
108
|
}
|
|
121
109
|
|
|
@@ -125,15 +113,16 @@ export async function previewSetsList(opts: {
|
|
|
125
113
|
versionLocalizationId: string
|
|
126
114
|
output?: string
|
|
127
115
|
}): Promise<void> {
|
|
128
|
-
const
|
|
129
|
-
id:
|
|
130
|
-
|
|
131
|
-
|
|
116
|
+
const result = await appStoreVersionLocalizationsAppPreviewSetsGetToManyRelated({
|
|
117
|
+
path: { id: opts.versionLocalizationId },
|
|
118
|
+
})
|
|
119
|
+
const data = throwOnError(result)
|
|
120
|
+
const items = data.data
|
|
132
121
|
const fmt = detectFormat(opts.output)
|
|
133
122
|
if (fmt === "json") { printJSON(items); return }
|
|
134
123
|
printTable(
|
|
135
124
|
["Set ID", "Preview Type"],
|
|
136
|
-
items.map(s => [s.id, s.attributes
|
|
125
|
+
items.map(s => [s.id, s.attributes?.previewType ?? "-"]),
|
|
137
126
|
`Preview Sets (${items.length})`,
|
|
138
127
|
)
|
|
139
128
|
}
|