@sitepong/fastnode 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -1
- package/dist/actions/index.cjs +891 -72
- package/dist/actions/index.cjs.map +1 -1
- package/dist/actions/index.mjs +892 -73
- package/dist/actions/index.mjs.map +1 -1
- package/dist/apple-session-jUzBrql5.d.cts +122 -0
- package/dist/apple-session-jUzBrql5.d.ts +122 -0
- package/dist/cert/index.cjs +17868 -24
- package/dist/cert/index.cjs.map +1 -1
- package/dist/cert/index.d.cts +5 -4
- package/dist/cert/index.d.ts +5 -4
- package/dist/cert/index.mjs +17853 -7
- package/dist/cert/index.mjs.map +1 -1
- package/dist/{cert-e5GAgAPb.d.ts → cert-RvXmdMke.d.ts} +2 -2
- package/dist/{cert-uLLdb5a7.d.cts → cert-eOoxGMN1.d.cts} +2 -2
- package/dist/cli/index.cjs +1364 -78
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.d.cts +3 -2
- package/dist/cli/index.d.ts +3 -2
- package/dist/cli/index.mjs +1365 -79
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/index.cjs +480 -31
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +3 -2
- package/dist/client/index.d.ts +3 -2
- package/dist/client/index.mjs +480 -31
- package/dist/client/index.mjs.map +1 -1
- package/dist/deliver/index.cjs +334 -13
- package/dist/deliver/index.cjs.map +1 -1
- package/dist/deliver/index.d.cts +4 -3
- package/dist/deliver/index.d.ts +4 -3
- package/dist/deliver/index.mjs +330 -15
- package/dist/deliver/index.mjs.map +1 -1
- package/dist/{enums-B609j2rb.d.cts → enums-yXNVh3UI.d.cts} +8 -1
- package/dist/{enums-B609j2rb.d.ts → enums-yXNVh3UI.d.ts} +8 -1
- package/dist/gradle/index.cjs +222 -0
- package/dist/gradle/index.cjs.map +1 -0
- package/dist/gradle/index.d.cts +1 -0
- package/dist/gradle/index.d.ts +1 -0
- package/dist/gradle/index.mjs +217 -0
- package/dist/gradle/index.mjs.map +1 -0
- package/dist/gym/index.d.cts +2 -2
- package/dist/gym/index.d.ts +2 -2
- package/dist/index-8djTPW8O.d.ts +104 -0
- package/dist/{index-DrUpRXRG.d.cts → index-B6-MJpO4.d.cts} +1 -1
- package/dist/{index-Clyf4-lu.d.cts → index-BE7bwNff.d.cts} +1 -1
- package/dist/index-BGhV0gS-.d.ts +65 -0
- package/dist/index-BaNcf7jt.d.cts +201 -0
- package/dist/{index-Di4Ic0EE.d.ts → index-BvyZ4uiw.d.ts} +3 -3
- package/dist/{index-CEldrbyz.d.ts → index-C01Rkrir.d.ts} +2 -2
- package/dist/{index-jeI44Q5G.d.ts → index-C9mHBJED.d.ts} +1 -1
- package/dist/{index-BgHagzj1.d.cts → index-CAEiXVWd.d.ts} +9 -1
- package/dist/index-CBf0-NUQ.d.ts +201 -0
- package/dist/index-CXJlvmB4.d.cts +63 -0
- package/dist/index-CXJlvmB4.d.ts +63 -0
- package/dist/{index-BNP7Bpu5.d.ts → index-D1GHEM3c.d.ts} +32 -3
- package/dist/index-DFstwgGK.d.cts +65 -0
- package/dist/{index-DrCOh0Vh.d.cts → index-DGkgRnZp.d.cts} +2 -2
- package/dist/{index-CtydPNxA.d.cts → index-DLJso7Vs.d.cts} +32 -3
- package/dist/{index-BN0iWhuw.d.cts → index-DWOLZNlz.d.cts} +2 -2
- package/dist/{index-BjkOUQcQ.d.cts → index-DfkIz7i0.d.cts} +18 -4
- package/dist/{index-EKU_G1G5.d.ts → index-DjC_gmnL.d.ts} +18 -4
- package/dist/index-DnHQ2uT2.d.cts +104 -0
- package/dist/{index-CdfgEZwh.d.cts → index-DrmS802s.d.cts} +356 -130
- package/dist/index-Dv-Mek07.d.cts +84 -0
- package/dist/index-Dv-Mek07.d.ts +84 -0
- package/dist/{index-DHxi-QPC.d.cts → index-icIH5e5V.d.cts} +3 -3
- package/dist/{index-mddpvrRX.d.ts → index-laE3_wm9.d.cts} +9 -1
- package/dist/{index-BwwpAlk2.d.ts → index-lsuS2R1T.d.ts} +356 -130
- package/dist/{index-DImN9PWc.d.ts → index-mEEB7An6.d.ts} +1 -1
- package/dist/{index-C2YLoFVl.d.ts → index-rTZOdMRE.d.ts} +2 -2
- package/dist/index.cjs +20496 -217
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +278 -22
- package/dist/index.d.ts +278 -22
- package/dist/index.mjs +20489 -220
- package/dist/index.mjs.map +1 -1
- package/dist/lane/index.cjs +891 -72
- package/dist/lane/index.cjs.map +1 -1
- package/dist/lane/index.mjs +892 -73
- package/dist/lane/index.mjs.map +1 -1
- package/dist/match/index.d.cts +6 -5
- package/dist/match/index.d.ts +6 -5
- package/dist/pem/index.d.cts +4 -3
- package/dist/pem/index.d.ts +4 -3
- package/dist/pilot/index.cjs +8 -4
- package/dist/pilot/index.cjs.map +1 -1
- package/dist/pilot/index.d.cts +4 -3
- package/dist/pilot/index.d.ts +4 -3
- package/dist/pilot/index.mjs +10 -6
- package/dist/pilot/index.mjs.map +1 -1
- package/dist/playstore/index.cjs +207 -0
- package/dist/playstore/index.cjs.map +1 -0
- package/dist/playstore/index.d.cts +1 -0
- package/dist/playstore/index.d.ts +1 -0
- package/dist/playstore/index.mjs +203 -0
- package/dist/playstore/index.mjs.map +1 -0
- package/dist/precheck/index.d.cts +4 -3
- package/dist/precheck/index.d.ts +4 -3
- package/dist/privacy/index.cjs +207 -0
- package/dist/privacy/index.cjs.map +1 -0
- package/dist/privacy/index.d.cts +2 -0
- package/dist/privacy/index.d.ts +2 -0
- package/dist/privacy/index.mjs +195 -0
- package/dist/privacy/index.mjs.map +1 -0
- package/dist/produce/index.cjs +38 -18
- package/dist/produce/index.cjs.map +1 -1
- package/dist/produce/index.d.cts +4 -3
- package/dist/produce/index.d.ts +4 -3
- package/dist/produce/index.mjs +38 -19
- package/dist/produce/index.mjs.map +1 -1
- package/dist/review/index.cjs +141 -0
- package/dist/review/index.cjs.map +1 -0
- package/dist/review/index.d.cts +2 -0
- package/dist/review/index.d.ts +2 -0
- package/dist/review/index.mjs +137 -0
- package/dist/review/index.mjs.map +1 -0
- package/dist/sigh/index.d.cts +4 -3
- package/dist/sigh/index.d.ts +4 -3
- package/dist/xcode/index.cjs +1 -1
- package/dist/xcode/index.cjs.map +1 -1
- package/dist/xcode/index.mjs +1 -1
- package/dist/xcode/index.mjs.map +1 -1
- package/package.json +27 -1
- package/dist/index-BbY_H_f6.d.ts +0 -99
- package/dist/index-XsMsVc3O.d.cts +0 -99
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// src/privacy/index.ts
|
|
2
|
+
var IRIS_BASE = "https://appstoreconnect.apple.com/iris/v1";
|
|
3
|
+
var OLYMPUS_SESSION = "https://appstoreconnect.apple.com/olympus/v1/session";
|
|
4
|
+
var DATA_USAGE_CATEGORIES = [
|
|
5
|
+
"PAYMENT_INFORMATION",
|
|
6
|
+
"CREDIT_AND_FRAUD",
|
|
7
|
+
"OTHER_FINANCIAL_INFO",
|
|
8
|
+
"PRECISE_LOCATION",
|
|
9
|
+
"COARSE_LOCATION",
|
|
10
|
+
"SENSITIVE_INFO",
|
|
11
|
+
"PHYSICAL_ADDRESS",
|
|
12
|
+
"EMAIL_ADDRESS",
|
|
13
|
+
"NAME",
|
|
14
|
+
"PHONE_NUMBER",
|
|
15
|
+
"OTHER_CONTACT_INFO",
|
|
16
|
+
"CONTACTS",
|
|
17
|
+
"EMAILS_OR_TEXT_MESSAGES",
|
|
18
|
+
"PHOTOS_OR_VIDEOS",
|
|
19
|
+
"AUDIO",
|
|
20
|
+
"GAMEPLAY_CONTENT",
|
|
21
|
+
"CUSTOMER_SUPPORT",
|
|
22
|
+
"OTHER_USER_CONTENT",
|
|
23
|
+
"BROWSING_HISTORY",
|
|
24
|
+
"SEARCH_HISTORY",
|
|
25
|
+
"USER_ID",
|
|
26
|
+
"DEVICE_ID",
|
|
27
|
+
"PURCHASE_HISTORY",
|
|
28
|
+
"PRODUCT_INTERACTION",
|
|
29
|
+
"ADVERTISING_DATA",
|
|
30
|
+
"OTHER_USAGE_DATA",
|
|
31
|
+
"CRASH_DATA",
|
|
32
|
+
"PERFORMANCE_DATA",
|
|
33
|
+
"OTHER_DIAGNOSTIC_DATA",
|
|
34
|
+
"OTHER_DATA",
|
|
35
|
+
"HEALTH",
|
|
36
|
+
"FITNESS"
|
|
37
|
+
];
|
|
38
|
+
var DATA_USAGE_PURPOSES = [
|
|
39
|
+
"THIRD_PARTY_ADVERTISING",
|
|
40
|
+
"DEVELOPERS_ADVERTISING",
|
|
41
|
+
"ANALYTICS",
|
|
42
|
+
"PRODUCT_PERSONALIZATION",
|
|
43
|
+
"APP_FUNCTIONALITY",
|
|
44
|
+
"OTHER_PURPOSES"
|
|
45
|
+
];
|
|
46
|
+
var DATA_PROTECTIONS = [
|
|
47
|
+
"DATA_USED_TO_TRACK_YOU",
|
|
48
|
+
"DATA_LINKED_TO_YOU",
|
|
49
|
+
"DATA_NOT_LINKED_TO_YOU",
|
|
50
|
+
"DATA_NOT_COLLECTED"
|
|
51
|
+
];
|
|
52
|
+
async function iris(session, method, path, body) {
|
|
53
|
+
const res = await fetch(path.startsWith("http") ? path : `${IRIS_BASE}${path}`, {
|
|
54
|
+
method,
|
|
55
|
+
headers: {
|
|
56
|
+
Cookie: cookieHeader(session),
|
|
57
|
+
Accept: "application/vnd.api+json, application/json",
|
|
58
|
+
"Content-Type": "application/vnd.api+json",
|
|
59
|
+
"X-Requested-With": "XMLHttpRequest"
|
|
60
|
+
},
|
|
61
|
+
body: body ? JSON.stringify(body) : void 0
|
|
62
|
+
});
|
|
63
|
+
absorbCookies(session, res);
|
|
64
|
+
const text = await res.text();
|
|
65
|
+
let parsed = null;
|
|
66
|
+
try {
|
|
67
|
+
parsed = text ? JSON.parse(text) : null;
|
|
68
|
+
} catch {
|
|
69
|
+
}
|
|
70
|
+
return { status: res.status, body: parsed, text };
|
|
71
|
+
}
|
|
72
|
+
function cookieHeader(session) {
|
|
73
|
+
return Object.entries(session.cookies).map(([k, v]) => `${k}=${v}`).join("; ");
|
|
74
|
+
}
|
|
75
|
+
function absorbCookies(session, res) {
|
|
76
|
+
for (const raw of res.headers.getSetCookie?.() ?? []) {
|
|
77
|
+
const m = raw.match(/^([^=]+)=([^;]*)/);
|
|
78
|
+
if (m) session.cookies[m[1]] = m[2];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function fail(what, r) {
|
|
82
|
+
const detail = r.body?.errors?.map((e) => e.detail ?? e.title).join("; ") || r.text.slice(0, 300);
|
|
83
|
+
throw new Error(`${what} failed (HTTP ${r.status}): ${detail}`);
|
|
84
|
+
}
|
|
85
|
+
async function selectProviderForApp(session, appId, onLog) {
|
|
86
|
+
const owns = async () => (await iris(session, "GET", `/apps/${appId}?fields[apps]=name`)).status === 200;
|
|
87
|
+
if (await owns()) return;
|
|
88
|
+
const res = await fetch(OLYMPUS_SESSION, { headers: { Cookie: cookieHeader(session), Accept: "application/json" } });
|
|
89
|
+
absorbCookies(session, res);
|
|
90
|
+
const info = await res.json().catch(() => null);
|
|
91
|
+
const providers = info?.availableProviders ?? [];
|
|
92
|
+
for (const p of providers) {
|
|
93
|
+
const sw = await fetch(OLYMPUS_SESSION, {
|
|
94
|
+
method: "POST",
|
|
95
|
+
headers: { Cookie: cookieHeader(session), "Content-Type": "application/json", Accept: "application/json" },
|
|
96
|
+
body: JSON.stringify({ provider: { providerId: p.providerId } })
|
|
97
|
+
});
|
|
98
|
+
absorbCookies(session, sw);
|
|
99
|
+
if (sw.ok && await owns()) {
|
|
100
|
+
onLog?.(`Switched to team "${p.name}"`);
|
|
101
|
+
session.teamId = String(p.providerId);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
throw new Error(`None of this Apple ID's ${providers.length} teams can see app ${appId}.`);
|
|
106
|
+
}
|
|
107
|
+
async function listAppDataUsages(session, appId) {
|
|
108
|
+
const all = [];
|
|
109
|
+
let next = `/apps/${appId}/dataUsages?include=category,grouping,purpose,dataProtection&limit=500`;
|
|
110
|
+
while (next) {
|
|
111
|
+
const r = await iris(session, "GET", next);
|
|
112
|
+
if (r.status !== 200) fail("List app data usages", r);
|
|
113
|
+
all.push(...(r.body?.data ?? []).map((d) => ({ id: d.id })));
|
|
114
|
+
next = r.body?.links?.next ?? null;
|
|
115
|
+
}
|
|
116
|
+
return all;
|
|
117
|
+
}
|
|
118
|
+
async function createAppDataUsage(session, input) {
|
|
119
|
+
const relationships = { app: { data: { type: "apps", id: input.appId } } };
|
|
120
|
+
if (input.category) relationships.category = { data: { type: "appDataUsageCategories", id: input.category } };
|
|
121
|
+
if (input.purpose) relationships.purpose = { data: { type: "appDataUsagePurposes", id: input.purpose } };
|
|
122
|
+
relationships.dataProtection = { data: { type: "appDataUsageDataProtections", id: input.dataProtection } };
|
|
123
|
+
const r = await iris(session, "POST", "/appDataUsages", { data: { type: "appDataUsages", relationships } });
|
|
124
|
+
if (r.status !== 201 && r.status !== 200) fail(`Create ${input.category ?? ""} ${input.purpose ?? ""} ${input.dataProtection}`.replace(/\s+/g, " "), r);
|
|
125
|
+
return r.body?.data?.id;
|
|
126
|
+
}
|
|
127
|
+
async function deleteAppDataUsage(session, id) {
|
|
128
|
+
const r = await iris(session, "DELETE", `/appDataUsages/${id}`);
|
|
129
|
+
if (r.status !== 204 && r.status !== 200) fail(`Delete app data usage ${id}`, r);
|
|
130
|
+
}
|
|
131
|
+
async function getAppDataUsagesPublishState(session, appId) {
|
|
132
|
+
const r = await iris(session, "GET", `/apps/${appId}/dataUsagePublishState`);
|
|
133
|
+
if (r.status !== 200) fail("Read privacy publish state", r);
|
|
134
|
+
return { id: r.body.data.id, published: Boolean(r.body.data.attributes?.published) };
|
|
135
|
+
}
|
|
136
|
+
async function publishAppDataUsages(session, publishStateId) {
|
|
137
|
+
const r = await iris(session, "PATCH", `/appDataUsagesPublishState/${publishStateId}`, {
|
|
138
|
+
data: { type: "appDataUsagesPublishState", id: publishStateId, attributes: { published: true } }
|
|
139
|
+
});
|
|
140
|
+
if (r.status !== 200) fail("Publish privacy details", r);
|
|
141
|
+
}
|
|
142
|
+
async function uploadAppPrivacyDetails(opts) {
|
|
143
|
+
const { session, appId, usages, skipPublish, onLog = () => {
|
|
144
|
+
} } = opts;
|
|
145
|
+
validateUsages(usages);
|
|
146
|
+
await selectProviderForApp(session, appId, onLog);
|
|
147
|
+
const existing = await listAppDataUsages(session, appId);
|
|
148
|
+
onLog(`Deleting ${existing.length} existing answer${existing.length === 1 ? "" : "s"}`);
|
|
149
|
+
for (const u of existing) await deleteAppDataUsage(session, u.id);
|
|
150
|
+
let created = 0;
|
|
151
|
+
for (const usage of usages) {
|
|
152
|
+
const purposes = usage.purposes?.length ? usage.purposes : [null];
|
|
153
|
+
for (const purpose of purposes) {
|
|
154
|
+
for (const protection of usage.data_protections) {
|
|
155
|
+
onLog(protection === "DATA_NOT_COLLECTED" ? `Setting ${protection}` : `Setting ${usage.category} and ${purpose} to ${protection}`);
|
|
156
|
+
await createAppDataUsage(session, { appId, category: usage.category ?? null, purpose, dataProtection: protection });
|
|
157
|
+
created++;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (skipPublish) {
|
|
162
|
+
onLog("Skipping publish");
|
|
163
|
+
return { deleted: existing.length, created, published: false };
|
|
164
|
+
}
|
|
165
|
+
const state = await getAppDataUsagesPublishState(session, appId);
|
|
166
|
+
await publishAppDataUsages(session, state.id);
|
|
167
|
+
onLog("Published");
|
|
168
|
+
return { deleted: existing.length, created, published: true };
|
|
169
|
+
}
|
|
170
|
+
function validateUsages(usages) {
|
|
171
|
+
if (!Array.isArray(usages) || usages.length === 0) throw new Error("No privacy usages given.");
|
|
172
|
+
const notCollected = usages.some((u) => u.data_protections?.includes("DATA_NOT_COLLECTED"));
|
|
173
|
+
if (notCollected && usages.length > 1) {
|
|
174
|
+
throw new Error("DATA_NOT_COLLECTED must be the only entry: an app cannot both collect nothing and collect something.");
|
|
175
|
+
}
|
|
176
|
+
const known = (list, v, what) => {
|
|
177
|
+
if (!list.includes(v)) throw new Error(`"${v}" is not an App Store Connect ${what}. Use one of: ${list.join(", ")}.`);
|
|
178
|
+
};
|
|
179
|
+
for (const u of usages) {
|
|
180
|
+
if (!u.data_protections?.length) throw new Error(`${u.category ?? "An entry"} has no data_protections.`);
|
|
181
|
+
if (u.category) known(DATA_USAGE_CATEGORIES, u.category, "data category");
|
|
182
|
+
for (const p of u.purposes ?? []) known(DATA_USAGE_PURPOSES, p, "purpose");
|
|
183
|
+
for (const d of u.data_protections) known(DATA_PROTECTIONS, d, "data protection");
|
|
184
|
+
if (u.data_protections.includes("DATA_NOT_COLLECTED")) continue;
|
|
185
|
+
if (!u.category) throw new Error("Every collected entry needs a category.");
|
|
186
|
+
if (!u.purposes?.length) throw new Error(`${u.category} needs at least one purpose.`);
|
|
187
|
+
const linked = u.data_protections.includes("DATA_LINKED_TO_YOU");
|
|
188
|
+
const unlinked = u.data_protections.includes("DATA_NOT_LINKED_TO_YOU");
|
|
189
|
+
if (linked && unlinked) throw new Error(`${u.category} cannot be both linked and not linked to the user.`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export { DATA_PROTECTIONS, DATA_USAGE_CATEGORIES, DATA_USAGE_PURPOSES, createAppDataUsage, deleteAppDataUsage, getAppDataUsagesPublishState, listAppDataUsages, publishAppDataUsages, selectProviderForApp, uploadAppPrivacyDetails, validateUsages };
|
|
194
|
+
//# sourceMappingURL=index.mjs.map
|
|
195
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/privacy/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * App Privacy details (\"nutrition labels\") for an app in App Store Connect.\n * 1:1 port of Fastlane's `upload_app_privacy_details_to_app_store` action and\n * Spaceship's AppDataUsage / AppDataUsagesPublishState models.\n *\n * The public App Store Connect API has no endpoint for privacy details — an\n * API key cannot set them. Fastlane goes through the iris API that App Store\n * Connect's own web UI uses, authenticated with an Apple ID session, and so\n * does this: pass the AppleSession from `loginWithAppleId` / the App Release\n * sign-in.\n *\n * Usages use Fastlane's JSON format, so an existing `app_privacy_details.json`\n * works unchanged:\n *\n * [\n * { \"category\": \"EMAIL_ADDRESS\", \"purposes\": [\"APP_FUNCTIONALITY\"], \"data_protections\": [\"DATA_LINKED_TO_YOU\"] },\n * { \"data_protections\": [\"DATA_NOT_COLLECTED\"] } // an app that collects nothing\n * ]\n *\n * As in Fastlane, the upload REPLACES everything: existing usages are deleted\n * first, then the new ones are created, then the answers are published.\n */\n\nimport type { AppleSession } from \"../client/apple-session.js\";\n\nconst IRIS_BASE = \"https://appstoreconnect.apple.com/iris/v1\";\nconst OLYMPUS_SESSION = \"https://appstoreconnect.apple.com/olympus/v1/session\";\n\n/** Every category App Store Connect accepts. Anything else is refused before existing answers are deleted. */\nexport const DATA_USAGE_CATEGORIES = [\n \"PAYMENT_INFORMATION\", \"CREDIT_AND_FRAUD\", \"OTHER_FINANCIAL_INFO\",\n \"PRECISE_LOCATION\", \"COARSE_LOCATION\", \"SENSITIVE_INFO\",\n \"PHYSICAL_ADDRESS\", \"EMAIL_ADDRESS\", \"NAME\", \"PHONE_NUMBER\", \"OTHER_CONTACT_INFO\",\n \"CONTACTS\", \"EMAILS_OR_TEXT_MESSAGES\", \"PHOTOS_OR_VIDEOS\", \"AUDIO\", \"GAMEPLAY_CONTENT\",\n \"CUSTOMER_SUPPORT\", \"OTHER_USER_CONTENT\", \"BROWSING_HISTORY\", \"SEARCH_HISTORY\",\n \"USER_ID\", \"DEVICE_ID\", \"PURCHASE_HISTORY\", \"PRODUCT_INTERACTION\", \"ADVERTISING_DATA\",\n \"OTHER_USAGE_DATA\", \"CRASH_DATA\", \"PERFORMANCE_DATA\", \"OTHER_DIAGNOSTIC_DATA\",\n \"OTHER_DATA\", \"HEALTH\", \"FITNESS\",\n] as const;\nexport const DATA_USAGE_PURPOSES = [\n \"THIRD_PARTY_ADVERTISING\", \"DEVELOPERS_ADVERTISING\", \"ANALYTICS\",\n \"PRODUCT_PERSONALIZATION\", \"APP_FUNCTIONALITY\", \"OTHER_PURPOSES\",\n] as const;\nexport const DATA_PROTECTIONS = [\n \"DATA_USED_TO_TRACK_YOU\", \"DATA_LINKED_TO_YOU\", \"DATA_NOT_LINKED_TO_YOU\", \"DATA_NOT_COLLECTED\",\n] as const;\n\nexport type DataUsageCategory =\n | \"PAYMENT_INFORMATION\" | \"CREDIT_AND_FRAUD\" | \"OTHER_FINANCIAL_INFO\"\n | \"PRECISE_LOCATION\" | \"COARSE_LOCATION\" | \"SENSITIVE_INFO\"\n | \"PHYSICAL_ADDRESS\" | \"EMAIL_ADDRESS\" | \"NAME\" | \"PHONE_NUMBER\" | \"OTHER_CONTACT_INFO\"\n | \"CONTACTS\" | \"EMAILS_OR_TEXT_MESSAGES\" | \"PHOTOS_OR_VIDEOS\" | \"AUDIO\" | \"GAMEPLAY_CONTENT\"\n | \"CUSTOMER_SUPPORT\" | \"OTHER_USER_CONTENT\" | \"BROWSING_HISTORY\" | \"SEARCH_HISTORY\"\n | \"USER_ID\" | \"DEVICE_ID\" | \"PURCHASE_HISTORY\" | \"PRODUCT_INTERACTION\" | \"ADVERTISING_DATA\"\n | \"OTHER_USAGE_DATA\" | \"CRASH_DATA\" | \"PERFORMANCE_DATA\" | \"OTHER_DIAGNOSTIC_DATA\"\n | \"OTHER_DATA\" | \"HEALTH\" | \"FITNESS\";\n\nexport type DataUsagePurpose =\n | \"THIRD_PARTY_ADVERTISING\" | \"DEVELOPERS_ADVERTISING\" | \"ANALYTICS\"\n | \"PRODUCT_PERSONALIZATION\" | \"APP_FUNCTIONALITY\" | \"OTHER_PURPOSES\";\n\nexport type DataProtection =\n | \"DATA_USED_TO_TRACK_YOU\" | \"DATA_LINKED_TO_YOU\" | \"DATA_NOT_LINKED_TO_YOU\" | \"DATA_NOT_COLLECTED\";\n\n/** One entry of Fastlane's app_privacy_details.json. */\nexport interface AppPrivacyUsage {\n category?: DataUsageCategory;\n purposes?: DataUsagePurpose[];\n data_protections: DataProtection[];\n}\n\nexport interface UploadAppPrivacyOptions {\n session: AppleSession;\n /** App Store Connect app id (the numeric Apple ID). */\n appId: string;\n usages: AppPrivacyUsage[];\n /** Leave the answers saved but unpublished (Fastlane's skip_publish). */\n skipPublish?: boolean;\n onLog?: (msg: string) => void;\n}\n\nexport interface UploadAppPrivacyResult {\n deleted: number;\n created: number;\n published: boolean;\n}\n\ninterface IrisResponse { status: number; body: any; text: string }\n\nasync function iris(session: AppleSession, method: string, path: string, body?: unknown): Promise<IrisResponse> {\n const res = await fetch(path.startsWith(\"http\") ? path : `${IRIS_BASE}${path}`, {\n method,\n headers: {\n Cookie: cookieHeader(session),\n Accept: \"application/vnd.api+json, application/json\",\n \"Content-Type\": \"application/vnd.api+json\",\n \"X-Requested-With\": \"XMLHttpRequest\",\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n absorbCookies(session, res);\n const text = await res.text();\n let parsed: any = null;\n try { parsed = text ? JSON.parse(text) : null; } catch { /* not JSON */ }\n return { status: res.status, body: parsed, text };\n}\n\nfunction cookieHeader(session: AppleSession): string {\n return Object.entries(session.cookies).map(([k, v]) => `${k}=${v}`).join(\"; \");\n}\n\nfunction absorbCookies(session: AppleSession, res: Response): void {\n for (const raw of res.headers.getSetCookie?.() ?? []) {\n const m = raw.match(/^([^=]+)=([^;]*)/);\n if (m) session.cookies[m[1]] = m[2];\n }\n}\n\nfunction fail(what: string, r: IrisResponse): never {\n const detail = r.body?.errors?.map((e: any) => e.detail ?? e.title).join(\"; \") || r.text.slice(0, 300);\n throw new Error(`${what} failed (HTTP ${r.status}): ${detail}`);\n}\n\n/**\n * Point the session at the App Store Connect provider (team) that owns the app.\n *\n * An Apple ID in several teams signs in to whichever one it used last, and\n * iris answers 404 for another team's app. Spaceship's `select_team` does the\n * same switch: POST the provider id to the olympus session.\n */\nexport async function selectProviderForApp(session: AppleSession, appId: string, onLog?: (m: string) => void): Promise<void> {\n const owns = async () => (await iris(session, \"GET\", `/apps/${appId}?fields[apps]=name`)).status === 200;\n if (await owns()) return;\n\n const res = await fetch(OLYMPUS_SESSION, { headers: { Cookie: cookieHeader(session), Accept: \"application/json\" } });\n absorbCookies(session, res);\n const info: any = await res.json().catch(() => null);\n const providers: Array<{ providerId: number; name: string }> = info?.availableProviders ?? [];\n for (const p of providers) {\n const sw = await fetch(OLYMPUS_SESSION, {\n method: \"POST\",\n headers: { Cookie: cookieHeader(session), \"Content-Type\": \"application/json\", Accept: \"application/json\" },\n body: JSON.stringify({ provider: { providerId: p.providerId } }),\n });\n absorbCookies(session, sw);\n if (sw.ok && (await owns())) {\n onLog?.(`Switched to team \"${p.name}\"`);\n session.teamId = String(p.providerId);\n return;\n }\n }\n throw new Error(`None of this Apple ID's ${providers.length} teams can see app ${appId}.`);\n}\n\n/** Existing privacy answers for an app. */\nexport async function listAppDataUsages(session: AppleSession, appId: string): Promise<Array<{ id: string }>> {\n const all: Array<{ id: string }> = [];\n let next: string | null = `/apps/${appId}/dataUsages?include=category,grouping,purpose,dataProtection&limit=500`;\n while (next) {\n const r = await iris(session, \"GET\", next);\n if (r.status !== 200) fail(\"List app data usages\", r);\n all.push(...(r.body?.data ?? []).map((d: any) => ({ id: d.id })));\n next = r.body?.links?.next ?? null;\n }\n return all;\n}\n\n/** Spaceship AppDataUsage.create — relationships are sent only when given. */\nexport async function createAppDataUsage(\n session: AppleSession,\n input: { appId: string; category?: string | null; purpose?: string | null; dataProtection: string },\n): Promise<string> {\n const relationships: Record<string, unknown> = { app: { data: { type: \"apps\", id: input.appId } } };\n if (input.category) relationships.category = { data: { type: \"appDataUsageCategories\", id: input.category } };\n if (input.purpose) relationships.purpose = { data: { type: \"appDataUsagePurposes\", id: input.purpose } };\n relationships.dataProtection = { data: { type: \"appDataUsageDataProtections\", id: input.dataProtection } };\n const r = await iris(session, \"POST\", \"/appDataUsages\", { data: { type: \"appDataUsages\", relationships } });\n if (r.status !== 201 && r.status !== 200) fail(`Create ${input.category ?? \"\"} ${input.purpose ?? \"\"} ${input.dataProtection}`.replace(/\\s+/g, \" \"), r);\n return r.body?.data?.id;\n}\n\nexport async function deleteAppDataUsage(session: AppleSession, id: string): Promise<void> {\n const r = await iris(session, \"DELETE\", `/appDataUsages/${id}`);\n if (r.status !== 204 && r.status !== 200) fail(`Delete app data usage ${id}`, r);\n}\n\nexport async function getAppDataUsagesPublishState(session: AppleSession, appId: string): Promise<{ id: string; published: boolean }> {\n const r = await iris(session, \"GET\", `/apps/${appId}/dataUsagePublishState`);\n if (r.status !== 200) fail(\"Read privacy publish state\", r);\n return { id: r.body.data.id, published: Boolean(r.body.data.attributes?.published) };\n}\n\nexport async function publishAppDataUsages(session: AppleSession, publishStateId: string): Promise<void> {\n const r = await iris(session, \"PATCH\", `/appDataUsagesPublishState/${publishStateId}`, {\n data: { type: \"appDataUsagesPublishState\", id: publishStateId, attributes: { published: true } },\n });\n if (r.status !== 200) fail(\"Publish privacy details\", r);\n}\n\n/** Fastlane's `upload_app_privacy_details_to_app_store`. Replaces all answers, then publishes. */\nexport async function uploadAppPrivacyDetails(opts: UploadAppPrivacyOptions): Promise<UploadAppPrivacyResult> {\n const { session, appId, usages, skipPublish, onLog = () => {} } = opts;\n validateUsages(usages);\n await selectProviderForApp(session, appId, onLog);\n\n const existing = await listAppDataUsages(session, appId);\n onLog(`Deleting ${existing.length} existing answer${existing.length === 1 ? \"\" : \"s\"}`);\n for (const u of existing) await deleteAppDataUsage(session, u.id);\n\n let created = 0;\n for (const usage of usages) {\n // \"Not collected\" has no purposes but still needs one AppDataUsage, so\n // iterate over [null] — the same trick Fastlane uses.\n const purposes: Array<string | null> = usage.purposes?.length ? usage.purposes : [null];\n for (const purpose of purposes) {\n for (const protection of usage.data_protections) {\n onLog(protection === \"DATA_NOT_COLLECTED\"\n ? `Setting ${protection}`\n : `Setting ${usage.category} and ${purpose} to ${protection}`);\n await createAppDataUsage(session, { appId, category: usage.category ?? null, purpose, dataProtection: protection });\n created++;\n }\n }\n }\n\n if (skipPublish) {\n onLog(\"Skipping publish\");\n return { deleted: existing.length, created, published: false };\n }\n const state = await getAppDataUsagesPublishState(session, appId);\n await publishAppDataUsages(session, state.id);\n onLog(\"Published\");\n return { deleted: existing.length, created, published: true };\n}\n\n/** Catch the answers App Store Connect would refuse, before deleting what is there. */\nexport function validateUsages(usages: AppPrivacyUsage[]): void {\n if (!Array.isArray(usages) || usages.length === 0) throw new Error(\"No privacy usages given.\");\n const notCollected = usages.some((u) => u.data_protections?.includes(\"DATA_NOT_COLLECTED\"));\n if (notCollected && usages.length > 1) {\n throw new Error(\"DATA_NOT_COLLECTED must be the only entry: an app cannot both collect nothing and collect something.\");\n }\n const known = (list: readonly string[], v: string, what: string) => {\n if (!list.includes(v)) throw new Error(`\"${v}\" is not an App Store Connect ${what}. Use one of: ${list.join(\", \")}.`);\n };\n for (const u of usages) {\n if (!u.data_protections?.length) throw new Error(`${u.category ?? \"An entry\"} has no data_protections.`);\n // Checked here, before anything is deleted: App Store Connect refuses an\n // unknown id only when that one answer is created, halfway through.\n if (u.category) known(DATA_USAGE_CATEGORIES, u.category, \"data category\");\n for (const p of u.purposes ?? []) known(DATA_USAGE_PURPOSES, p, \"purpose\");\n for (const d of u.data_protections) known(DATA_PROTECTIONS, d, \"data protection\");\n if (u.data_protections.includes(\"DATA_NOT_COLLECTED\")) continue;\n if (!u.category) throw new Error(\"Every collected entry needs a category.\");\n if (!u.purposes?.length) throw new Error(`${u.category} needs at least one purpose.`);\n const linked = u.data_protections.includes(\"DATA_LINKED_TO_YOU\");\n const unlinked = u.data_protections.includes(\"DATA_NOT_LINKED_TO_YOU\");\n if (linked && unlinked) throw new Error(`${u.category} cannot be both linked and not linked to the user.`);\n }\n}\n"]}
|
package/dist/produce/index.cjs
CHANGED
|
@@ -149,6 +149,30 @@ async function enableServices(options) {
|
|
|
149
149
|
});
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
|
+
async function associateAppGroups(options) {
|
|
153
|
+
if (!options.appGroups?.length) return;
|
|
154
|
+
await options.portalClient.enableAppGroups(options.bundleIdId).catch(() => {
|
|
155
|
+
});
|
|
156
|
+
const existing = await options.portalClient.listAppGroups();
|
|
157
|
+
const appGroupIds = [];
|
|
158
|
+
for (const group of options.appGroups) {
|
|
159
|
+
let record = existing.find((ag) => ag.identifier === group.identifier);
|
|
160
|
+
if (!record) {
|
|
161
|
+
record = await options.portalClient.createAppGroup({
|
|
162
|
+
name: group.name,
|
|
163
|
+
identifier: group.identifier
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
const id = record?.applicationGroup ?? record?.applicationGroupId ?? record?.appGroupId ?? record?.id;
|
|
167
|
+
if (id) appGroupIds.push(id);
|
|
168
|
+
}
|
|
169
|
+
if (appGroupIds.length) {
|
|
170
|
+
await options.portalClient.assignAppGroups({
|
|
171
|
+
appIdId: options.bundleIdId,
|
|
172
|
+
appGroupIds
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
}
|
|
152
176
|
async function createApp(options) {
|
|
153
177
|
const existing = await options.client.apps.findByBundleId(options.bundleIdentifier);
|
|
154
178
|
if (existing) return existing;
|
|
@@ -167,29 +191,25 @@ async function createApp(options) {
|
|
|
167
191
|
});
|
|
168
192
|
}
|
|
169
193
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
data: { type: "bundleIds", id: bundleId.id }
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
194
|
+
if (options.appGroups?.length && options.portalClient) {
|
|
195
|
+
await associateAppGroups({
|
|
196
|
+
portalClient: options.portalClient,
|
|
197
|
+
bundleIdId: bundleId.id,
|
|
198
|
+
appGroups: options.appGroups
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
return options.client.apps.create({
|
|
202
|
+
bundleIdentifier: options.bundleIdentifier,
|
|
203
|
+
bundleIdId: bundleId.id,
|
|
204
|
+
appName: options.appName,
|
|
205
|
+
sku: options.sku ?? `${options.bundleIdentifier}.${Date.now()}`,
|
|
206
|
+
primaryLocale: options.primaryLocale
|
|
187
207
|
});
|
|
188
|
-
return response.data;
|
|
189
208
|
}
|
|
190
209
|
|
|
191
210
|
exports.SERVICE_NAME_TO_CAPABILITY = SERVICE_NAME_TO_CAPABILITY;
|
|
192
211
|
exports.addCapability = addCapability;
|
|
212
|
+
exports.associateAppGroups = associateAppGroups;
|
|
193
213
|
exports.buildCapabilitySettings = buildCapabilitySettings;
|
|
194
214
|
exports.createApp = createApp;
|
|
195
215
|
exports.enableServices = enableServices;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/produce/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["import type { AppStoreConnectClient } from \"../client/index.js\";\nimport type { BundleId, App, BundleIdPlatform, CapabilityType } from \"../types/index.js\";\nimport type { CapabilitySettingInput } from \"../types/capability.js\";\n\nexport interface ProduceOptions {\n client: AppStoreConnectClient;\n bundleIdentifier: string;\n appName: string;\n platform?: BundleIdPlatform;\n sku?: string;\n primaryLocale?: string;\n companyName?: string;\n enableServices?: CapabilityType[];\n}\n\n/**\n * Map from Fastlane's `produce` service name → App Store Connect\n * `capabilityType`. Ported 1:1 from `produce/lib/produce/service.rb`'s\n * `valid_services_for` list and `update` method, covering every service\n * that Fastlane supports.\n */\nexport const SERVICE_NAME_TO_CAPABILITY: Record<string, CapabilityType> = {\n access_wifi: \"ACCESS_WIFI_INFORMATION\",\n app_attest: \"APP_ATTEST\",\n // Fastlane uses singular `app_group` — see service.rb line 59 & 105.\n app_group: \"APP_GROUPS\",\n apple_pay: \"APPLE_PAY\",\n associated_domains: \"ASSOCIATED_DOMAINS\",\n auto_fill_credential: \"AUTOFILL_CREDENTIAL_PROVIDER\",\n car_play_audio_app: \"CARPLAY_PLAYABLE_CONTENT\",\n car_play_messaging_app: \"CARPLAY_MESSAGING\",\n car_play_navigation_app: \"CARPLAY_NAVIGATION\",\n car_play_voip_calling_app: \"CARPLAY_VOIP\",\n class_kit: \"CLASSKIT\",\n declared_age_range: \"DECLARED_AGE_RANGE\",\n icloud: \"ICLOUD\",\n critical_alerts: \"CRITICAL_ALERTS\",\n custom_network_protocol: \"NETWORK_CUSTOM_PROTOCOL\",\n data_protection: \"DATA_PROTECTION\",\n extended_virtual_address_space: \"EXTENDED_VIRTUAL_ADDRESSING\",\n file_provider_testing_mode: \"FILEPROVIDER_TESTINGMODE\",\n family_controls: \"FAMILY_CONTROLS\",\n fonts: \"FONT_INSTALLATION\",\n game_center: \"GAME_CENTER\",\n health_kit: \"HEALTHKIT\",\n hls_interstitial_preview: \"HLS_INTERSTITIAL_PREVIEW\",\n home_kit: \"HOMEKIT\",\n hotspot: \"HOT_SPOT\",\n hotspot_helper: \"HOTSPOT_HELPER_MANAGED\",\n in_app_purchase: \"IN_APP_PURCHASE\",\n inter_app_audio: \"INTER_APP_AUDIO\",\n low_latency_hls: \"COREMEDIA_HLS_LOW_LATENCY\",\n managed_associated_domains: \"MDM_MANAGED_ASSOCIATED_DOMAINS\",\n maps: \"MAPS\",\n multipath: \"MULTIPATH\",\n network_extension: \"NETWORK_EXTENSIONS\",\n nfc_tag_reading: \"NFC_TAG_READING\",\n personal_vpn: \"PERSONAL_VPN\",\n push_notification: \"PUSH_NOTIFICATIONS\",\n sign_in_with_apple: \"APPLE_ID_AUTH\",\n siri_kit: \"SIRIKIT\",\n system_extension: \"SYSTEM_EXTENSION_INSTALL\",\n user_management: \"USER_MANAGEMENT\",\n wallet: \"WALLET\",\n wireless_accessory: \"WIRELESS_ACCESSORY_CONFIGURATION\",\n driver_kit: \"DRIVERKIT\",\n driver_kit_endpoint_security: \"DRIVERKIT_ENDPOINT_SECURITY\",\n driver_kit_family_hid_device: \"DRIVERKIT_HID_DEVICE\",\n driver_kit_family_networking: \"DRIVERKIT_NETWORKING\",\n driver_kit_family_serial: \"DRIVERKIT_SERIAL\",\n driver_kit_hid_event_service: \"DRIVERKIT_HID_EVENT_SERVICE\",\n driver_kit_transport_hid: \"DRIVERKIT_HID\",\n multitasking_camera_access: \"IPAD_CAMERA_MULTITASKING\",\n sf_universal_link_api: \"SFUNIVERSALLINK_API\",\n vp9_decoder: \"VP9_DECODER\",\n music_kit: \"MUSIC_KIT\",\n shazam_kit: \"SHAZAM_KIT\",\n communication_notifications: \"USERNOTIFICATIONS_COMMUNICATION\",\n group_activities: \"GROUP_ACTIVITIES\",\n health_kit_estimate_recalibration: \"HEALTHKIT_RECALIBRATE_ESTIMATES\",\n time_sensitive_notifications: \"USERNOTIFICATIONS_TIMESENSITIVE\",\n};\n\n/**\n * Build the `settings` payload for a capability whose service value is\n * more than a plain boolean. Mirrors Fastlane's\n * `Produce::Service#build_settings_for` applied per-service.\n *\n * Returns `undefined` when the service doesn't carry settings or the\n * value is just `true`/`false`.\n */\nexport function buildCapabilitySettings(\n serviceName: string,\n value: string | boolean\n): CapabilitySettingInput[] | undefined {\n if (value === true || value === false) return undefined;\n\n const wrap = (\n key: string,\n optionKey: string\n ): CapabilitySettingInput[] => [{ key, options: [{ key: optionKey }] }];\n\n switch (serviceName) {\n case \"data_protection\":\n switch (value) {\n case \"complete\":\n return wrap(\"DATA_PROTECTION_PERMISSION_LEVEL\", \"COMPLETE_PROTECTION\");\n case \"unlessopen\":\n return wrap(\"DATA_PROTECTION_PERMISSION_LEVEL\", \"PROTECTED_UNLESS_OPEN\");\n case \"untilfirstauth\":\n return wrap(\n \"DATA_PROTECTION_PERMISSION_LEVEL\",\n \"PROTECTED_UNTIL_FIRST_USER_AUTH\"\n );\n default:\n throw new Error(\n `Unknown value for data_protection: '${value}'. Valid values: 'complete', 'unlessopen', 'untilfirstauth'`\n );\n }\n case \"icloud\":\n switch (value) {\n case \"xcode6_compatible\":\n return wrap(\"ICLOUD_VERSION\", \"XCODE_6\");\n case \"xcode5_compatible\":\n return wrap(\"ICLOUD_VERSION\", \"XCODE_5\");\n default:\n throw new Error(\n `Unknown value for icloud: '${value}'. Valid values: 'xcode6_compatible', 'xcode5_compatible'`\n );\n }\n case \"game_center\":\n switch (value) {\n case \"mac\":\n return wrap(\"GAME_CENTER_SETTING\", \"GAME_CENTER_MAC\");\n case \"ios\":\n return wrap(\"GAME_CENTER_SETTING\", \"GAME_CENTER_IOS\");\n default:\n throw new Error(\n `Unknown value for game_center: '${value}'. Valid values: 'ios', 'mac'`\n );\n }\n case \"sign_in_with_apple\":\n return wrap(\"APPLE_ID_AUTH_APP_CONSENT\", \"PRIMARY_APP_CONSENT\");\n default:\n return undefined;\n }\n}\n\nexport async function registerBundleId(options: {\n client: AppStoreConnectClient;\n identifier: string;\n name: string;\n platform?: BundleIdPlatform;\n}): Promise<BundleId> {\n // Check if already exists (idempotent)\n const existing = await options.client.bundleIds.find(options.identifier);\n if (existing) return existing;\n\n return options.client.bundleIds.create({\n identifier: options.identifier,\n name: options.name,\n platform: options.platform ?? \"IOS\",\n });\n}\n\nexport async function addCapability(options: {\n client: AppStoreConnectClient;\n bundleIdId: string;\n capabilityType: CapabilityType;\n settings?: CapabilitySettingInput[];\n}): Promise<void> {\n await options.client.capabilities.enable({\n bundleIdId: options.bundleIdId,\n capabilityType: options.capabilityType,\n settings: options.settings,\n });\n}\n\nexport async function removeCapability(options: {\n client: AppStoreConnectClient;\n capabilityId: string;\n}): Promise<void> {\n await options.client.capabilities.disable(options.capabilityId);\n}\n\nexport async function listCapabilities(options: {\n client: AppStoreConnectClient;\n bundleIdId: string;\n}) {\n return options.client.capabilities.listForBundleId(options.bundleIdId);\n}\n\nexport async function enableServices(options: {\n client: AppStoreConnectClient;\n bundleIdId: string;\n /**\n * Service names (Fastlane style, e.g. `data_protection`, `icloud`).\n * Pass either a plain list of names or a record of name → value, where\n * the value either is `true` or one of the per-service variants handled\n * by `buildCapabilitySettings`.\n */\n services: string[] | Record<string, string | boolean>;\n}): Promise<void> {\n const entries: Array<[string, string | boolean]> = Array.isArray(\n options.services\n )\n ? options.services.map((s) => [s, true])\n : Object.entries(options.services);\n\n for (const [service, value] of entries) {\n if (value === false) continue;\n const capType = SERVICE_NAME_TO_CAPABILITY[service];\n if (!capType) continue;\n const settings = buildCapabilitySettings(service, value);\n await addCapability({\n client: options.client,\n bundleIdId: options.bundleIdId,\n capabilityType: capType,\n settings,\n });\n }\n}\n\nexport async function createApp(options: ProduceOptions): Promise<App> {\n // Check if app already exists\n const existing = await options.client.apps.findByBundleId(options.bundleIdentifier);\n if (existing) return existing;\n\n // Register bundle ID\n const bundleId = await registerBundleId({\n client: options.client,\n identifier: options.bundleIdentifier,\n name: options.appName,\n platform: options.platform,\n });\n\n // Enable services\n if (options.enableServices) {\n for (const service of options.enableServices) {\n await addCapability({\n client: options.client,\n bundleIdId: bundleId.id,\n capabilityType: service,\n });\n }\n }\n\n // Create app on App Store Connect\n const sku = options.sku ?? `${options.bundleIdentifier}.${Date.now()}`;\n const primaryLocale = options.primaryLocale ?? \"en-US\";\n\n const response = await options.client.http.post<any>(\"/v1/apps\", {\n data: {\n type: \"apps\",\n attributes: {\n bundleId: options.bundleIdentifier,\n name: options.appName,\n sku,\n primaryLocale,\n },\n relationships: {\n bundleId: {\n data: { type: \"bundleIds\", id: bundleId.id },\n },\n },\n },\n });\n\n return response.data;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/produce/index.ts"],"names":[],"mappings":";;;AAwBO,IAAM,0BAAA,GAA6D;AAAA,EACxE,WAAA,EAAa,yBAAA;AAAA,EACb,UAAA,EAAY,YAAA;AAAA;AAAA,EAEZ,SAAA,EAAW,YAAA;AAAA,EACX,SAAA,EAAW,WAAA;AAAA,EACX,kBAAA,EAAoB,oBAAA;AAAA,EACpB,oBAAA,EAAsB,8BAAA;AAAA,EACtB,kBAAA,EAAoB,0BAAA;AAAA,EACpB,sBAAA,EAAwB,mBAAA;AAAA,EACxB,uBAAA,EAAyB,oBAAA;AAAA,EACzB,yBAAA,EAA2B,cAAA;AAAA,EAC3B,SAAA,EAAW,UAAA;AAAA,EACX,kBAAA,EAAoB,oBAAA;AAAA,EACpB,MAAA,EAAQ,QAAA;AAAA,EACR,eAAA,EAAiB,iBAAA;AAAA,EACjB,uBAAA,EAAyB,yBAAA;AAAA,EACzB,eAAA,EAAiB,iBAAA;AAAA,EACjB,8BAAA,EAAgC,6BAAA;AAAA,EAChC,0BAAA,EAA4B,0BAAA;AAAA,EAC5B,eAAA,EAAiB,iBAAA;AAAA,EACjB,KAAA,EAAO,mBAAA;AAAA,EACP,WAAA,EAAa,aAAA;AAAA,EACb,UAAA,EAAY,WAAA;AAAA,EACZ,wBAAA,EAA0B,0BAAA;AAAA,EAC1B,QAAA,EAAU,SAAA;AAAA,EACV,OAAA,EAAS,UAAA;AAAA,EACT,cAAA,EAAgB,wBAAA;AAAA,EAChB,eAAA,EAAiB,iBAAA;AAAA,EACjB,eAAA,EAAiB,iBAAA;AAAA,EACjB,eAAA,EAAiB,2BAAA;AAAA,EACjB,0BAAA,EAA4B,gCAAA;AAAA,EAC5B,IAAA,EAAM,MAAA;AAAA,EACN,SAAA,EAAW,WAAA;AAAA,EACX,iBAAA,EAAmB,oBAAA;AAAA,EACnB,eAAA,EAAiB,iBAAA;AAAA,EACjB,YAAA,EAAc,cAAA;AAAA,EACd,iBAAA,EAAmB,oBAAA;AAAA,EACnB,kBAAA,EAAoB,eAAA;AAAA,EACpB,QAAA,EAAU,SAAA;AAAA,EACV,gBAAA,EAAkB,0BAAA;AAAA,EAClB,eAAA,EAAiB,iBAAA;AAAA,EACjB,MAAA,EAAQ,QAAA;AAAA,EACR,kBAAA,EAAoB,kCAAA;AAAA,EACpB,UAAA,EAAY,WAAA;AAAA,EACZ,4BAAA,EAA8B,6BAAA;AAAA,EAC9B,4BAAA,EAA8B,sBAAA;AAAA,EAC9B,4BAAA,EAA8B,sBAAA;AAAA,EAC9B,wBAAA,EAA0B,kBAAA;AAAA,EAC1B,4BAAA,EAA8B,6BAAA;AAAA,EAC9B,wBAAA,EAA0B,eAAA;AAAA,EAC1B,0BAAA,EAA4B,0BAAA;AAAA,EAC5B,qBAAA,EAAuB,qBAAA;AAAA,EACvB,WAAA,EAAa,aAAA;AAAA,EACb,SAAA,EAAW,WAAA;AAAA,EACX,UAAA,EAAY,YAAA;AAAA,EACZ,2BAAA,EAA6B,iCAAA;AAAA,EAC7B,gBAAA,EAAkB,kBAAA;AAAA,EAClB,iCAAA,EAAmC,iCAAA;AAAA,EACnC,4BAAA,EAA8B;AAChC;AAUO,SAAS,uBAAA,CACd,aACA,KAAA,EACsC;AACtC,EAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,KAAA,KAAU,KAAA,EAAO,OAAO,MAAA;AAE9C,EAAA,MAAM,IAAA,GAAO,CACX,GAAA,EACA,SAAA,KAC6B,CAAC,EAAE,GAAA,EAAK,OAAA,EAAS,CAAC,EAAE,GAAA,EAAK,SAAA,EAAW,GAAG,CAAA;AAEtE,EAAA,QAAQ,WAAA;AAAa,IACnB,KAAK,iBAAA;AACH,MAAA,QAAQ,KAAA;AAAO,QACb,KAAK,UAAA;AACH,UAAA,OAAO,IAAA,CAAK,oCAAoC,qBAAqB,CAAA;AAAA,QACvE,KAAK,YAAA;AACH,UAAA,OAAO,IAAA,CAAK,oCAAoC,uBAAuB,CAAA;AAAA,QACzE,KAAK,gBAAA;AACH,UAAA,OAAO,IAAA;AAAA,YACL,kCAAA;AAAA,YACA;AAAA,WACF;AAAA,QACF;AACE,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,uCAAuC,KAAK,CAAA,2DAAA;AAAA,WAC9C;AAAA;AACJ,IACF,KAAK,QAAA;AACH,MAAA,QAAQ,KAAA;AAAO,QACb,KAAK,mBAAA;AACH,UAAA,OAAO,IAAA,CAAK,kBAAkB,SAAS,CAAA;AAAA,QACzC,KAAK,mBAAA;AACH,UAAA,OAAO,IAAA,CAAK,kBAAkB,SAAS,CAAA;AAAA,QACzC;AACE,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,8BAA8B,KAAK,CAAA,yDAAA;AAAA,WACrC;AAAA;AACJ,IACF,KAAK,aAAA;AACH,MAAA,QAAQ,KAAA;AAAO,QACb,KAAK,KAAA;AACH,UAAA,OAAO,IAAA,CAAK,uBAAuB,iBAAiB,CAAA;AAAA,QACtD,KAAK,KAAA;AACH,UAAA,OAAO,IAAA,CAAK,uBAAuB,iBAAiB,CAAA;AAAA,QACtD;AACE,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,mCAAmC,KAAK,CAAA,6BAAA;AAAA,WAC1C;AAAA;AACJ,IACF,KAAK,oBAAA;AACH,MAAA,OAAO,IAAA,CAAK,6BAA6B,qBAAqB,CAAA;AAAA,IAChE;AACE,MAAA,OAAO,MAAA;AAAA;AAEb;AAEA,eAAsB,iBAAiB,OAAA,EAKjB;AAEpB,EAAA,MAAM,WAAW,MAAM,OAAA,CAAQ,OAAO,SAAA,CAAU,IAAA,CAAK,QAAQ,UAAU,CAAA;AACvE,EAAA,IAAI,UAAU,OAAO,QAAA;AAErB,EAAA,OAAO,OAAA,CAAQ,MAAA,CAAO,SAAA,CAAU,MAAA,CAAO;AAAA,IACrC,YAAY,OAAA,CAAQ,UAAA;AAAA,IACpB,MAAM,OAAA,CAAQ,IAAA;AAAA,IACd,QAAA,EAAU,QAAQ,QAAA,IAAY;AAAA,GAC/B,CAAA;AACH;AAEA,eAAsB,cAAc,OAAA,EAKlB;AAChB,EAAA,MAAM,OAAA,CAAQ,MAAA,CAAO,YAAA,CAAa,MAAA,CAAO;AAAA,IACvC,YAAY,OAAA,CAAQ,UAAA;AAAA,IACpB,gBAAgB,OAAA,CAAQ,cAAA;AAAA,IACxB,UAAU,OAAA,CAAQ;AAAA,GACnB,CAAA;AACH;AAEA,eAAsB,iBAAiB,OAAA,EAGrB;AAChB,EAAA,MAAM,OAAA,CAAQ,MAAA,CAAO,YAAA,CAAa,OAAA,CAAQ,QAAQ,YAAY,CAAA;AAChE;AAEA,eAAsB,iBAAiB,OAAA,EAGpC;AACD,EAAA,OAAO,OAAA,CAAQ,MAAA,CAAO,YAAA,CAAa,eAAA,CAAgB,QAAQ,UAAU,CAAA;AACvE;AAEA,eAAsB,eAAe,OAAA,EAUnB;AAChB,EAAA,MAAM,UAA6C,KAAA,CAAM,OAAA;AAAA,IACvD,OAAA,CAAQ;AAAA,GACV,GACI,OAAA,CAAQ,QAAA,CAAS,GAAA,CAAI,CAAC,CAAA,KAAM,CAAC,CAAA,EAAG,IAAI,CAAC,CAAA,GACrC,MAAA,CAAO,OAAA,CAAQ,QAAQ,QAAQ,CAAA;AAEnC,EAAA,KAAA,MAAW,CAAC,OAAA,EAAS,KAAK,CAAA,IAAK,OAAA,EAAS;AACtC,IAAA,IAAI,UAAU,KAAA,EAAO;AACrB,IAAA,MAAM,OAAA,GAAU,2BAA2B,OAAO,CAAA;AAClD,IAAA,IAAI,CAAC,OAAA,EAAS;AACd,IAAA,MAAM,QAAA,GAAW,uBAAA,CAAwB,OAAA,EAAS,KAAK,CAAA;AACvD,IAAA,MAAM,aAAA,CAAc;AAAA,MAClB,QAAQ,OAAA,CAAQ,MAAA;AAAA,MAChB,YAAY,OAAA,CAAQ,UAAA;AAAA,MACpB,cAAA,EAAgB,OAAA;AAAA,MAChB;AAAA,KACD,CAAA;AAAA,EACH;AACF;AAEA,eAAsB,mBAAmB,OAAA,EAIvB;AAChB,EAAA,IAAI,CAAC,OAAA,CAAQ,SAAA,EAAW,MAAA,EAAQ;AAMhC,EAAA,MAAM,QAAQ,YAAA,CAAa,eAAA,CAAgB,QAAQ,UAAU,CAAA,CAAE,MAAM,MAAM;AAAA,EAAC,CAAC,CAAA;AAE7E,EAAA,MAAM,QAAA,GAAW,MAAM,OAAA,CAAQ,YAAA,CAAa,aAAA,EAAc;AAC1D,EAAA,MAAM,cAAwB,EAAC;AAC/B,EAAA,KAAA,MAAW,KAAA,IAAS,QAAQ,SAAA,EAAW;AACrC,IAAA,IAAI,MAAA,GAAS,SAAS,IAAA,CAAK,CAAC,OAAY,EAAA,CAAG,UAAA,KAAe,MAAM,UAAU,CAAA;AAC1E,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAA,GAAS,MAAM,OAAA,CAAQ,YAAA,CAAa,cAAA,CAAe;AAAA,QACjD,MAAM,KAAA,CAAM,IAAA;AAAA,QACZ,YAAY,KAAA,CAAM;AAAA,OACnB,CAAA;AAAA,IACH;AACA,IAAA,MAAM,KACJ,MAAA,EAAQ,gBAAA,IAAoB,QAAQ,kBAAA,IAAsB,MAAA,EAAQ,cAAc,MAAA,EAAQ,EAAA;AAC1F,IAAA,IAAI,EAAA,EAAI,WAAA,CAAY,IAAA,CAAK,EAAE,CAAA;AAAA,EAC7B;AAEA,EAAA,IAAI,YAAY,MAAA,EAAQ;AACtB,IAAA,MAAM,OAAA,CAAQ,aAAa,eAAA,CAAgB;AAAA,MACzC,SAAS,OAAA,CAAQ,UAAA;AAAA,MACjB;AAAA,KACD,CAAA;AAAA,EACH;AACF;AAEA,eAAsB,UAAU,OAAA,EAAuC;AAErE,EAAA,MAAM,WAAW,MAAM,OAAA,CAAQ,OAAO,IAAA,CAAK,cAAA,CAAe,QAAQ,gBAAgB,CAAA;AAClF,EAAA,IAAI,UAAU,OAAO,QAAA;AAGrB,EAAA,MAAM,QAAA,GAAW,MAAM,gBAAA,CAAiB;AAAA,IACtC,QAAQ,OAAA,CAAQ,MAAA;AAAA,IAChB,YAAY,OAAA,CAAQ,gBAAA;AAAA,IACpB,MAAM,OAAA,CAAQ,OAAA;AAAA,IACd,UAAU,OAAA,CAAQ;AAAA,GACnB,CAAA;AAGD,EAAA,IAAI,QAAQ,cAAA,EAAgB;AAC1B,IAAA,KAAA,MAAW,OAAA,IAAW,QAAQ,cAAA,EAAgB;AAC5C,MAAA,MAAM,aAAA,CAAc;AAAA,QAClB,QAAQ,OAAA,CAAQ,MAAA;AAAA,QAChB,YAAY,QAAA,CAAS,EAAA;AAAA,QACrB,cAAA,EAAgB;AAAA,OACjB,CAAA;AAAA,IACH;AAAA,EACF;AAGA,EAAA,IAAI,OAAA,CAAQ,SAAA,EAAW,MAAA,IAAU,OAAA,CAAQ,YAAA,EAAc;AACrD,IAAA,MAAM,kBAAA,CAAmB;AAAA,MACvB,cAAc,OAAA,CAAQ,YAAA;AAAA,MACtB,YAAY,QAAA,CAAS,EAAA;AAAA,MACrB,WAAW,OAAA,CAAQ;AAAA,KACpB,CAAA;AAAA,EACH;AAGA,EAAA,OAAO,OAAA,CAAQ,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO;AAAA,IAChC,kBAAkB,OAAA,CAAQ,gBAAA;AAAA,IAC1B,YAAY,QAAA,CAAS,EAAA;AAAA,IACrB,SAAS,OAAA,CAAQ,OAAA;AAAA,IACjB,GAAA,EAAK,QAAQ,GAAA,IAAO,CAAA,EAAG,QAAQ,gBAAgB,CAAA,CAAA,EAAI,IAAA,CAAK,GAAA,EAAK,CAAA,CAAA;AAAA,IAC7D,eAAe,OAAA,CAAQ;AAAA,GACxB,CAAA;AACH","file":"index.cjs","sourcesContent":["import type { AppStoreConnectClient } from \"../client/index.js\";\nimport type { BundleId, App, BundleIdPlatform, CapabilityType } from \"../types/index.js\";\nimport type { CapabilitySettingInput } from \"../types/capability.js\";\nimport type { PortalClient } from \"../client/portal.js\";\n\nexport interface ProduceOptions {\n client: AppStoreConnectClient;\n bundleIdentifier: string;\n appName: string;\n platform?: BundleIdPlatform;\n sku?: string;\n primaryLocale?: string;\n companyName?: string;\n enableServices?: CapabilityType[];\n appGroups?: Array<{ name: string; identifier: string }>;\n portalClient?: PortalClient;\n}\n\n/**\n * Map from Fastlane's `produce` service name → App Store Connect\n * `capabilityType`. Ported 1:1 from `produce/lib/produce/service.rb`'s\n * `valid_services_for` list and `update` method, covering every service\n * that Fastlane supports.\n */\nexport const SERVICE_NAME_TO_CAPABILITY: Record<string, CapabilityType> = {\n access_wifi: \"ACCESS_WIFI_INFORMATION\",\n app_attest: \"APP_ATTEST\",\n // Fastlane uses singular `app_group` — see service.rb line 59 & 105.\n app_group: \"APP_GROUPS\",\n apple_pay: \"APPLE_PAY\",\n associated_domains: \"ASSOCIATED_DOMAINS\",\n auto_fill_credential: \"AUTOFILL_CREDENTIAL_PROVIDER\",\n car_play_audio_app: \"CARPLAY_PLAYABLE_CONTENT\",\n car_play_messaging_app: \"CARPLAY_MESSAGING\",\n car_play_navigation_app: \"CARPLAY_NAVIGATION\",\n car_play_voip_calling_app: \"CARPLAY_VOIP\",\n class_kit: \"CLASSKIT\",\n declared_age_range: \"DECLARED_AGE_RANGE\",\n icloud: \"ICLOUD\",\n critical_alerts: \"CRITICAL_ALERTS\",\n custom_network_protocol: \"NETWORK_CUSTOM_PROTOCOL\",\n data_protection: \"DATA_PROTECTION\",\n extended_virtual_address_space: \"EXTENDED_VIRTUAL_ADDRESSING\",\n file_provider_testing_mode: \"FILEPROVIDER_TESTINGMODE\",\n family_controls: \"FAMILY_CONTROLS\",\n fonts: \"FONT_INSTALLATION\",\n game_center: \"GAME_CENTER\",\n health_kit: \"HEALTHKIT\",\n hls_interstitial_preview: \"HLS_INTERSTITIAL_PREVIEW\",\n home_kit: \"HOMEKIT\",\n hotspot: \"HOT_SPOT\",\n hotspot_helper: \"HOTSPOT_HELPER_MANAGED\",\n in_app_purchase: \"IN_APP_PURCHASE\",\n inter_app_audio: \"INTER_APP_AUDIO\",\n low_latency_hls: \"COREMEDIA_HLS_LOW_LATENCY\",\n managed_associated_domains: \"MDM_MANAGED_ASSOCIATED_DOMAINS\",\n maps: \"MAPS\",\n multipath: \"MULTIPATH\",\n network_extension: \"NETWORK_EXTENSIONS\",\n nfc_tag_reading: \"NFC_TAG_READING\",\n personal_vpn: \"PERSONAL_VPN\",\n push_notification: \"PUSH_NOTIFICATIONS\",\n sign_in_with_apple: \"APPLE_ID_AUTH\",\n siri_kit: \"SIRIKIT\",\n system_extension: \"SYSTEM_EXTENSION_INSTALL\",\n user_management: \"USER_MANAGEMENT\",\n wallet: \"WALLET\",\n wireless_accessory: \"WIRELESS_ACCESSORY_CONFIGURATION\",\n driver_kit: \"DRIVERKIT\",\n driver_kit_endpoint_security: \"DRIVERKIT_ENDPOINT_SECURITY\",\n driver_kit_family_hid_device: \"DRIVERKIT_HID_DEVICE\",\n driver_kit_family_networking: \"DRIVERKIT_NETWORKING\",\n driver_kit_family_serial: \"DRIVERKIT_SERIAL\",\n driver_kit_hid_event_service: \"DRIVERKIT_HID_EVENT_SERVICE\",\n driver_kit_transport_hid: \"DRIVERKIT_HID\",\n multitasking_camera_access: \"IPAD_CAMERA_MULTITASKING\",\n sf_universal_link_api: \"SFUNIVERSALLINK_API\",\n vp9_decoder: \"VP9_DECODER\",\n music_kit: \"MUSIC_KIT\",\n shazam_kit: \"SHAZAM_KIT\",\n communication_notifications: \"USERNOTIFICATIONS_COMMUNICATION\",\n group_activities: \"GROUP_ACTIVITIES\",\n health_kit_estimate_recalibration: \"HEALTHKIT_RECALIBRATE_ESTIMATES\",\n time_sensitive_notifications: \"USERNOTIFICATIONS_TIMESENSITIVE\",\n};\n\n/**\n * Build the `settings` payload for a capability whose service value is\n * more than a plain boolean. Mirrors Fastlane's\n * `Produce::Service#build_settings_for` applied per-service.\n *\n * Returns `undefined` when the service doesn't carry settings or the\n * value is just `true`/`false`.\n */\nexport function buildCapabilitySettings(\n serviceName: string,\n value: string | boolean\n): CapabilitySettingInput[] | undefined {\n if (value === true || value === false) return undefined;\n\n const wrap = (\n key: string,\n optionKey: string\n ): CapabilitySettingInput[] => [{ key, options: [{ key: optionKey }] }];\n\n switch (serviceName) {\n case \"data_protection\":\n switch (value) {\n case \"complete\":\n return wrap(\"DATA_PROTECTION_PERMISSION_LEVEL\", \"COMPLETE_PROTECTION\");\n case \"unlessopen\":\n return wrap(\"DATA_PROTECTION_PERMISSION_LEVEL\", \"PROTECTED_UNLESS_OPEN\");\n case \"untilfirstauth\":\n return wrap(\n \"DATA_PROTECTION_PERMISSION_LEVEL\",\n \"PROTECTED_UNTIL_FIRST_USER_AUTH\"\n );\n default:\n throw new Error(\n `Unknown value for data_protection: '${value}'. Valid values: 'complete', 'unlessopen', 'untilfirstauth'`\n );\n }\n case \"icloud\":\n switch (value) {\n case \"xcode6_compatible\":\n return wrap(\"ICLOUD_VERSION\", \"XCODE_6\");\n case \"xcode5_compatible\":\n return wrap(\"ICLOUD_VERSION\", \"XCODE_5\");\n default:\n throw new Error(\n `Unknown value for icloud: '${value}'. Valid values: 'xcode6_compatible', 'xcode5_compatible'`\n );\n }\n case \"game_center\":\n switch (value) {\n case \"mac\":\n return wrap(\"GAME_CENTER_SETTING\", \"GAME_CENTER_MAC\");\n case \"ios\":\n return wrap(\"GAME_CENTER_SETTING\", \"GAME_CENTER_IOS\");\n default:\n throw new Error(\n `Unknown value for game_center: '${value}'. Valid values: 'ios', 'mac'`\n );\n }\n case \"sign_in_with_apple\":\n return wrap(\"APPLE_ID_AUTH_APP_CONSENT\", \"PRIMARY_APP_CONSENT\");\n default:\n return undefined;\n }\n}\n\nexport async function registerBundleId(options: {\n client: AppStoreConnectClient;\n identifier: string;\n name: string;\n platform?: BundleIdPlatform;\n}): Promise<BundleId> {\n // Check if already exists (idempotent)\n const existing = await options.client.bundleIds.find(options.identifier);\n if (existing) return existing;\n\n return options.client.bundleIds.create({\n identifier: options.identifier,\n name: options.name,\n platform: options.platform ?? \"IOS\",\n });\n}\n\nexport async function addCapability(options: {\n client: AppStoreConnectClient;\n bundleIdId: string;\n capabilityType: CapabilityType;\n settings?: CapabilitySettingInput[];\n}): Promise<void> {\n await options.client.capabilities.enable({\n bundleIdId: options.bundleIdId,\n capabilityType: options.capabilityType,\n settings: options.settings,\n });\n}\n\nexport async function removeCapability(options: {\n client: AppStoreConnectClient;\n capabilityId: string;\n}): Promise<void> {\n await options.client.capabilities.disable(options.capabilityId);\n}\n\nexport async function listCapabilities(options: {\n client: AppStoreConnectClient;\n bundleIdId: string;\n}) {\n return options.client.capabilities.listForBundleId(options.bundleIdId);\n}\n\nexport async function enableServices(options: {\n client: AppStoreConnectClient;\n bundleIdId: string;\n /**\n * Service names (Fastlane style, e.g. `data_protection`, `icloud`).\n * Pass either a plain list of names or a record of name → value, where\n * the value either is `true` or one of the per-service variants handled\n * by `buildCapabilitySettings`.\n */\n services: string[] | Record<string, string | boolean>;\n}): Promise<void> {\n const entries: Array<[string, string | boolean]> = Array.isArray(\n options.services\n )\n ? options.services.map((s) => [s, true])\n : Object.entries(options.services);\n\n for (const [service, value] of entries) {\n if (value === false) continue;\n const capType = SERVICE_NAME_TO_CAPABILITY[service];\n if (!capType) continue;\n const settings = buildCapabilitySettings(service, value);\n await addCapability({\n client: options.client,\n bundleIdId: options.bundleIdId,\n capabilityType: capType,\n settings,\n });\n }\n}\n\nexport async function associateAppGroups(options: {\n portalClient: PortalClient;\n bundleIdId: string;\n appGroups: Array<{ name: string; identifier: string }>;\n}): Promise<void> {\n if (!options.appGroups?.length) return;\n\n // Enable the App Groups capability on the App ID once, then associate all\n // requested groups in a single declarative call. Apple's internal group\n // handle comes back under `applicationGroup` (Spaceship's app_group_id) —\n // NOT the human `group.com.…` identifier, which association rejects.\n await options.portalClient.enableAppGroups(options.bundleIdId).catch(() => {});\n\n const existing = await options.portalClient.listAppGroups();\n const appGroupIds: string[] = [];\n for (const group of options.appGroups) {\n let record = existing.find((ag: any) => ag.identifier === group.identifier);\n if (!record) {\n record = await options.portalClient.createAppGroup({\n name: group.name,\n identifier: group.identifier,\n });\n }\n const id =\n record?.applicationGroup ?? record?.applicationGroupId ?? record?.appGroupId ?? record?.id;\n if (id) appGroupIds.push(id);\n }\n\n if (appGroupIds.length) {\n await options.portalClient.assignAppGroups({\n appIdId: options.bundleIdId,\n appGroupIds,\n });\n }\n}\n\nexport async function createApp(options: ProduceOptions): Promise<App> {\n // Check if app already exists\n const existing = await options.client.apps.findByBundleId(options.bundleIdentifier);\n if (existing) return existing;\n\n // Register bundle ID\n const bundleId = await registerBundleId({\n client: options.client,\n identifier: options.bundleIdentifier,\n name: options.appName,\n platform: options.platform,\n });\n\n // Enable services\n if (options.enableServices) {\n for (const service of options.enableServices) {\n await addCapability({\n client: options.client,\n bundleIdId: bundleId.id,\n capabilityType: service,\n });\n }\n }\n\n // Create/associate app groups (requires PortalClient with Apple ID session)\n if (options.appGroups?.length && options.portalClient) {\n await associateAppGroups({\n portalClient: options.portalClient,\n bundleIdId: bundleId.id,\n appGroups: options.appGroups,\n });\n }\n\n // Create app on App Store Connect\n return options.client.apps.create({\n bundleIdentifier: options.bundleIdentifier,\n bundleIdId: bundleId.id,\n appName: options.appName,\n sku: options.sku ?? `${options.bundleIdentifier}.${Date.now()}`,\n primaryLocale: options.primaryLocale,\n });\n}\n"]}
|
package/dist/produce/index.d.cts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import '../index-
|
|
2
|
-
import '../enums-
|
|
3
|
-
export { P as ProduceOptions, S as SERVICE_NAME_TO_CAPABILITY, a as addCapability, b as buildCapabilitySettings,
|
|
1
|
+
import '../index-DrmS802s.cjs';
|
|
2
|
+
import '../enums-yXNVh3UI.cjs';
|
|
3
|
+
export { P as ProduceOptions, S as SERVICE_NAME_TO_CAPABILITY, a as addCapability, d as associateAppGroups, b as buildCapabilitySettings, f as createApp, e as enableServices, l as listCapabilities, r as registerBundleId, c as removeCapability } from '../index-DfkIz7i0.cjs';
|
|
4
|
+
import '../apple-session-jUzBrql5.cjs';
|
package/dist/produce/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import '../index-
|
|
2
|
-
import '../enums-
|
|
3
|
-
export { P as ProduceOptions, S as SERVICE_NAME_TO_CAPABILITY, a as addCapability, b as buildCapabilitySettings,
|
|
1
|
+
import '../index-lsuS2R1T.js';
|
|
2
|
+
import '../enums-yXNVh3UI.js';
|
|
3
|
+
export { P as ProduceOptions, S as SERVICE_NAME_TO_CAPABILITY, a as addCapability, d as associateAppGroups, b as buildCapabilitySettings, f as createApp, e as enableServices, l as listCapabilities, r as registerBundleId, c as removeCapability } from '../index-DjC_gmnL.js';
|
|
4
|
+
import '../apple-session-jUzBrql5.js';
|
package/dist/produce/index.mjs
CHANGED
|
@@ -147,6 +147,30 @@ async function enableServices(options) {
|
|
|
147
147
|
});
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
|
+
async function associateAppGroups(options) {
|
|
151
|
+
if (!options.appGroups?.length) return;
|
|
152
|
+
await options.portalClient.enableAppGroups(options.bundleIdId).catch(() => {
|
|
153
|
+
});
|
|
154
|
+
const existing = await options.portalClient.listAppGroups();
|
|
155
|
+
const appGroupIds = [];
|
|
156
|
+
for (const group of options.appGroups) {
|
|
157
|
+
let record = existing.find((ag) => ag.identifier === group.identifier);
|
|
158
|
+
if (!record) {
|
|
159
|
+
record = await options.portalClient.createAppGroup({
|
|
160
|
+
name: group.name,
|
|
161
|
+
identifier: group.identifier
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
const id = record?.applicationGroup ?? record?.applicationGroupId ?? record?.appGroupId ?? record?.id;
|
|
165
|
+
if (id) appGroupIds.push(id);
|
|
166
|
+
}
|
|
167
|
+
if (appGroupIds.length) {
|
|
168
|
+
await options.portalClient.assignAppGroups({
|
|
169
|
+
appIdId: options.bundleIdId,
|
|
170
|
+
appGroupIds
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
150
174
|
async function createApp(options) {
|
|
151
175
|
const existing = await options.client.apps.findByBundleId(options.bundleIdentifier);
|
|
152
176
|
if (existing) return existing;
|
|
@@ -165,27 +189,22 @@ async function createApp(options) {
|
|
|
165
189
|
});
|
|
166
190
|
}
|
|
167
191
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
data: { type: "bundleIds", id: bundleId.id }
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
192
|
+
if (options.appGroups?.length && options.portalClient) {
|
|
193
|
+
await associateAppGroups({
|
|
194
|
+
portalClient: options.portalClient,
|
|
195
|
+
bundleIdId: bundleId.id,
|
|
196
|
+
appGroups: options.appGroups
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
return options.client.apps.create({
|
|
200
|
+
bundleIdentifier: options.bundleIdentifier,
|
|
201
|
+
bundleIdId: bundleId.id,
|
|
202
|
+
appName: options.appName,
|
|
203
|
+
sku: options.sku ?? `${options.bundleIdentifier}.${Date.now()}`,
|
|
204
|
+
primaryLocale: options.primaryLocale
|
|
185
205
|
});
|
|
186
|
-
return response.data;
|
|
187
206
|
}
|
|
188
207
|
|
|
189
|
-
export { SERVICE_NAME_TO_CAPABILITY, addCapability, buildCapabilitySettings, createApp, enableServices, listCapabilities, registerBundleId, removeCapability };
|
|
208
|
+
export { SERVICE_NAME_TO_CAPABILITY, addCapability, associateAppGroups, buildCapabilitySettings, createApp, enableServices, listCapabilities, registerBundleId, removeCapability };
|
|
190
209
|
//# sourceMappingURL=index.mjs.map
|
|
191
210
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/produce/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type { AppStoreConnectClient } from \"../client/index.js\";\nimport type { BundleId, App, BundleIdPlatform, CapabilityType } from \"../types/index.js\";\nimport type { CapabilitySettingInput } from \"../types/capability.js\";\n\nexport interface ProduceOptions {\n client: AppStoreConnectClient;\n bundleIdentifier: string;\n appName: string;\n platform?: BundleIdPlatform;\n sku?: string;\n primaryLocale?: string;\n companyName?: string;\n enableServices?: CapabilityType[];\n}\n\n/**\n * Map from Fastlane's `produce` service name → App Store Connect\n * `capabilityType`. Ported 1:1 from `produce/lib/produce/service.rb`'s\n * `valid_services_for` list and `update` method, covering every service\n * that Fastlane supports.\n */\nexport const SERVICE_NAME_TO_CAPABILITY: Record<string, CapabilityType> = {\n access_wifi: \"ACCESS_WIFI_INFORMATION\",\n app_attest: \"APP_ATTEST\",\n // Fastlane uses singular `app_group` — see service.rb line 59 & 105.\n app_group: \"APP_GROUPS\",\n apple_pay: \"APPLE_PAY\",\n associated_domains: \"ASSOCIATED_DOMAINS\",\n auto_fill_credential: \"AUTOFILL_CREDENTIAL_PROVIDER\",\n car_play_audio_app: \"CARPLAY_PLAYABLE_CONTENT\",\n car_play_messaging_app: \"CARPLAY_MESSAGING\",\n car_play_navigation_app: \"CARPLAY_NAVIGATION\",\n car_play_voip_calling_app: \"CARPLAY_VOIP\",\n class_kit: \"CLASSKIT\",\n declared_age_range: \"DECLARED_AGE_RANGE\",\n icloud: \"ICLOUD\",\n critical_alerts: \"CRITICAL_ALERTS\",\n custom_network_protocol: \"NETWORK_CUSTOM_PROTOCOL\",\n data_protection: \"DATA_PROTECTION\",\n extended_virtual_address_space: \"EXTENDED_VIRTUAL_ADDRESSING\",\n file_provider_testing_mode: \"FILEPROVIDER_TESTINGMODE\",\n family_controls: \"FAMILY_CONTROLS\",\n fonts: \"FONT_INSTALLATION\",\n game_center: \"GAME_CENTER\",\n health_kit: \"HEALTHKIT\",\n hls_interstitial_preview: \"HLS_INTERSTITIAL_PREVIEW\",\n home_kit: \"HOMEKIT\",\n hotspot: \"HOT_SPOT\",\n hotspot_helper: \"HOTSPOT_HELPER_MANAGED\",\n in_app_purchase: \"IN_APP_PURCHASE\",\n inter_app_audio: \"INTER_APP_AUDIO\",\n low_latency_hls: \"COREMEDIA_HLS_LOW_LATENCY\",\n managed_associated_domains: \"MDM_MANAGED_ASSOCIATED_DOMAINS\",\n maps: \"MAPS\",\n multipath: \"MULTIPATH\",\n network_extension: \"NETWORK_EXTENSIONS\",\n nfc_tag_reading: \"NFC_TAG_READING\",\n personal_vpn: \"PERSONAL_VPN\",\n push_notification: \"PUSH_NOTIFICATIONS\",\n sign_in_with_apple: \"APPLE_ID_AUTH\",\n siri_kit: \"SIRIKIT\",\n system_extension: \"SYSTEM_EXTENSION_INSTALL\",\n user_management: \"USER_MANAGEMENT\",\n wallet: \"WALLET\",\n wireless_accessory: \"WIRELESS_ACCESSORY_CONFIGURATION\",\n driver_kit: \"DRIVERKIT\",\n driver_kit_endpoint_security: \"DRIVERKIT_ENDPOINT_SECURITY\",\n driver_kit_family_hid_device: \"DRIVERKIT_HID_DEVICE\",\n driver_kit_family_networking: \"DRIVERKIT_NETWORKING\",\n driver_kit_family_serial: \"DRIVERKIT_SERIAL\",\n driver_kit_hid_event_service: \"DRIVERKIT_HID_EVENT_SERVICE\",\n driver_kit_transport_hid: \"DRIVERKIT_HID\",\n multitasking_camera_access: \"IPAD_CAMERA_MULTITASKING\",\n sf_universal_link_api: \"SFUNIVERSALLINK_API\",\n vp9_decoder: \"VP9_DECODER\",\n music_kit: \"MUSIC_KIT\",\n shazam_kit: \"SHAZAM_KIT\",\n communication_notifications: \"USERNOTIFICATIONS_COMMUNICATION\",\n group_activities: \"GROUP_ACTIVITIES\",\n health_kit_estimate_recalibration: \"HEALTHKIT_RECALIBRATE_ESTIMATES\",\n time_sensitive_notifications: \"USERNOTIFICATIONS_TIMESENSITIVE\",\n};\n\n/**\n * Build the `settings` payload for a capability whose service value is\n * more than a plain boolean. Mirrors Fastlane's\n * `Produce::Service#build_settings_for` applied per-service.\n *\n * Returns `undefined` when the service doesn't carry settings or the\n * value is just `true`/`false`.\n */\nexport function buildCapabilitySettings(\n serviceName: string,\n value: string | boolean\n): CapabilitySettingInput[] | undefined {\n if (value === true || value === false) return undefined;\n\n const wrap = (\n key: string,\n optionKey: string\n ): CapabilitySettingInput[] => [{ key, options: [{ key: optionKey }] }];\n\n switch (serviceName) {\n case \"data_protection\":\n switch (value) {\n case \"complete\":\n return wrap(\"DATA_PROTECTION_PERMISSION_LEVEL\", \"COMPLETE_PROTECTION\");\n case \"unlessopen\":\n return wrap(\"DATA_PROTECTION_PERMISSION_LEVEL\", \"PROTECTED_UNLESS_OPEN\");\n case \"untilfirstauth\":\n return wrap(\n \"DATA_PROTECTION_PERMISSION_LEVEL\",\n \"PROTECTED_UNTIL_FIRST_USER_AUTH\"\n );\n default:\n throw new Error(\n `Unknown value for data_protection: '${value}'. Valid values: 'complete', 'unlessopen', 'untilfirstauth'`\n );\n }\n case \"icloud\":\n switch (value) {\n case \"xcode6_compatible\":\n return wrap(\"ICLOUD_VERSION\", \"XCODE_6\");\n case \"xcode5_compatible\":\n return wrap(\"ICLOUD_VERSION\", \"XCODE_5\");\n default:\n throw new Error(\n `Unknown value for icloud: '${value}'. Valid values: 'xcode6_compatible', 'xcode5_compatible'`\n );\n }\n case \"game_center\":\n switch (value) {\n case \"mac\":\n return wrap(\"GAME_CENTER_SETTING\", \"GAME_CENTER_MAC\");\n case \"ios\":\n return wrap(\"GAME_CENTER_SETTING\", \"GAME_CENTER_IOS\");\n default:\n throw new Error(\n `Unknown value for game_center: '${value}'. Valid values: 'ios', 'mac'`\n );\n }\n case \"sign_in_with_apple\":\n return wrap(\"APPLE_ID_AUTH_APP_CONSENT\", \"PRIMARY_APP_CONSENT\");\n default:\n return undefined;\n }\n}\n\nexport async function registerBundleId(options: {\n client: AppStoreConnectClient;\n identifier: string;\n name: string;\n platform?: BundleIdPlatform;\n}): Promise<BundleId> {\n // Check if already exists (idempotent)\n const existing = await options.client.bundleIds.find(options.identifier);\n if (existing) return existing;\n\n return options.client.bundleIds.create({\n identifier: options.identifier,\n name: options.name,\n platform: options.platform ?? \"IOS\",\n });\n}\n\nexport async function addCapability(options: {\n client: AppStoreConnectClient;\n bundleIdId: string;\n capabilityType: CapabilityType;\n settings?: CapabilitySettingInput[];\n}): Promise<void> {\n await options.client.capabilities.enable({\n bundleIdId: options.bundleIdId,\n capabilityType: options.capabilityType,\n settings: options.settings,\n });\n}\n\nexport async function removeCapability(options: {\n client: AppStoreConnectClient;\n capabilityId: string;\n}): Promise<void> {\n await options.client.capabilities.disable(options.capabilityId);\n}\n\nexport async function listCapabilities(options: {\n client: AppStoreConnectClient;\n bundleIdId: string;\n}) {\n return options.client.capabilities.listForBundleId(options.bundleIdId);\n}\n\nexport async function enableServices(options: {\n client: AppStoreConnectClient;\n bundleIdId: string;\n /**\n * Service names (Fastlane style, e.g. `data_protection`, `icloud`).\n * Pass either a plain list of names or a record of name → value, where\n * the value either is `true` or one of the per-service variants handled\n * by `buildCapabilitySettings`.\n */\n services: string[] | Record<string, string | boolean>;\n}): Promise<void> {\n const entries: Array<[string, string | boolean]> = Array.isArray(\n options.services\n )\n ? options.services.map((s) => [s, true])\n : Object.entries(options.services);\n\n for (const [service, value] of entries) {\n if (value === false) continue;\n const capType = SERVICE_NAME_TO_CAPABILITY[service];\n if (!capType) continue;\n const settings = buildCapabilitySettings(service, value);\n await addCapability({\n client: options.client,\n bundleIdId: options.bundleIdId,\n capabilityType: capType,\n settings,\n });\n }\n}\n\nexport async function createApp(options: ProduceOptions): Promise<App> {\n // Check if app already exists\n const existing = await options.client.apps.findByBundleId(options.bundleIdentifier);\n if (existing) return existing;\n\n // Register bundle ID\n const bundleId = await registerBundleId({\n client: options.client,\n identifier: options.bundleIdentifier,\n name: options.appName,\n platform: options.platform,\n });\n\n // Enable services\n if (options.enableServices) {\n for (const service of options.enableServices) {\n await addCapability({\n client: options.client,\n bundleIdId: bundleId.id,\n capabilityType: service,\n });\n }\n }\n\n // Create app on App Store Connect\n const sku = options.sku ?? `${options.bundleIdentifier}.${Date.now()}`;\n const primaryLocale = options.primaryLocale ?? \"en-US\";\n\n const response = await options.client.http.post<any>(\"/v1/apps\", {\n data: {\n type: \"apps\",\n attributes: {\n bundleId: options.bundleIdentifier,\n name: options.appName,\n sku,\n primaryLocale,\n },\n relationships: {\n bundleId: {\n data: { type: \"bundleIds\", id: bundleId.id },\n },\n },\n },\n });\n\n return response.data;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/produce/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import type { AppStoreConnectClient } from \"../client/index.js\";\nimport type { BundleId, App, BundleIdPlatform, CapabilityType } from \"../types/index.js\";\nimport type { CapabilitySettingInput } from \"../types/capability.js\";\nimport type { PortalClient } from \"../client/portal.js\";\n\nexport interface ProduceOptions {\n client: AppStoreConnectClient;\n bundleIdentifier: string;\n appName: string;\n platform?: BundleIdPlatform;\n sku?: string;\n primaryLocale?: string;\n companyName?: string;\n enableServices?: CapabilityType[];\n appGroups?: Array<{ name: string; identifier: string }>;\n portalClient?: PortalClient;\n}\n\n/**\n * Map from Fastlane's `produce` service name → App Store Connect\n * `capabilityType`. Ported 1:1 from `produce/lib/produce/service.rb`'s\n * `valid_services_for` list and `update` method, covering every service\n * that Fastlane supports.\n */\nexport const SERVICE_NAME_TO_CAPABILITY: Record<string, CapabilityType> = {\n access_wifi: \"ACCESS_WIFI_INFORMATION\",\n app_attest: \"APP_ATTEST\",\n // Fastlane uses singular `app_group` — see service.rb line 59 & 105.\n app_group: \"APP_GROUPS\",\n apple_pay: \"APPLE_PAY\",\n associated_domains: \"ASSOCIATED_DOMAINS\",\n auto_fill_credential: \"AUTOFILL_CREDENTIAL_PROVIDER\",\n car_play_audio_app: \"CARPLAY_PLAYABLE_CONTENT\",\n car_play_messaging_app: \"CARPLAY_MESSAGING\",\n car_play_navigation_app: \"CARPLAY_NAVIGATION\",\n car_play_voip_calling_app: \"CARPLAY_VOIP\",\n class_kit: \"CLASSKIT\",\n declared_age_range: \"DECLARED_AGE_RANGE\",\n icloud: \"ICLOUD\",\n critical_alerts: \"CRITICAL_ALERTS\",\n custom_network_protocol: \"NETWORK_CUSTOM_PROTOCOL\",\n data_protection: \"DATA_PROTECTION\",\n extended_virtual_address_space: \"EXTENDED_VIRTUAL_ADDRESSING\",\n file_provider_testing_mode: \"FILEPROVIDER_TESTINGMODE\",\n family_controls: \"FAMILY_CONTROLS\",\n fonts: \"FONT_INSTALLATION\",\n game_center: \"GAME_CENTER\",\n health_kit: \"HEALTHKIT\",\n hls_interstitial_preview: \"HLS_INTERSTITIAL_PREVIEW\",\n home_kit: \"HOMEKIT\",\n hotspot: \"HOT_SPOT\",\n hotspot_helper: \"HOTSPOT_HELPER_MANAGED\",\n in_app_purchase: \"IN_APP_PURCHASE\",\n inter_app_audio: \"INTER_APP_AUDIO\",\n low_latency_hls: \"COREMEDIA_HLS_LOW_LATENCY\",\n managed_associated_domains: \"MDM_MANAGED_ASSOCIATED_DOMAINS\",\n maps: \"MAPS\",\n multipath: \"MULTIPATH\",\n network_extension: \"NETWORK_EXTENSIONS\",\n nfc_tag_reading: \"NFC_TAG_READING\",\n personal_vpn: \"PERSONAL_VPN\",\n push_notification: \"PUSH_NOTIFICATIONS\",\n sign_in_with_apple: \"APPLE_ID_AUTH\",\n siri_kit: \"SIRIKIT\",\n system_extension: \"SYSTEM_EXTENSION_INSTALL\",\n user_management: \"USER_MANAGEMENT\",\n wallet: \"WALLET\",\n wireless_accessory: \"WIRELESS_ACCESSORY_CONFIGURATION\",\n driver_kit: \"DRIVERKIT\",\n driver_kit_endpoint_security: \"DRIVERKIT_ENDPOINT_SECURITY\",\n driver_kit_family_hid_device: \"DRIVERKIT_HID_DEVICE\",\n driver_kit_family_networking: \"DRIVERKIT_NETWORKING\",\n driver_kit_family_serial: \"DRIVERKIT_SERIAL\",\n driver_kit_hid_event_service: \"DRIVERKIT_HID_EVENT_SERVICE\",\n driver_kit_transport_hid: \"DRIVERKIT_HID\",\n multitasking_camera_access: \"IPAD_CAMERA_MULTITASKING\",\n sf_universal_link_api: \"SFUNIVERSALLINK_API\",\n vp9_decoder: \"VP9_DECODER\",\n music_kit: \"MUSIC_KIT\",\n shazam_kit: \"SHAZAM_KIT\",\n communication_notifications: \"USERNOTIFICATIONS_COMMUNICATION\",\n group_activities: \"GROUP_ACTIVITIES\",\n health_kit_estimate_recalibration: \"HEALTHKIT_RECALIBRATE_ESTIMATES\",\n time_sensitive_notifications: \"USERNOTIFICATIONS_TIMESENSITIVE\",\n};\n\n/**\n * Build the `settings` payload for a capability whose service value is\n * more than a plain boolean. Mirrors Fastlane's\n * `Produce::Service#build_settings_for` applied per-service.\n *\n * Returns `undefined` when the service doesn't carry settings or the\n * value is just `true`/`false`.\n */\nexport function buildCapabilitySettings(\n serviceName: string,\n value: string | boolean\n): CapabilitySettingInput[] | undefined {\n if (value === true || value === false) return undefined;\n\n const wrap = (\n key: string,\n optionKey: string\n ): CapabilitySettingInput[] => [{ key, options: [{ key: optionKey }] }];\n\n switch (serviceName) {\n case \"data_protection\":\n switch (value) {\n case \"complete\":\n return wrap(\"DATA_PROTECTION_PERMISSION_LEVEL\", \"COMPLETE_PROTECTION\");\n case \"unlessopen\":\n return wrap(\"DATA_PROTECTION_PERMISSION_LEVEL\", \"PROTECTED_UNLESS_OPEN\");\n case \"untilfirstauth\":\n return wrap(\n \"DATA_PROTECTION_PERMISSION_LEVEL\",\n \"PROTECTED_UNTIL_FIRST_USER_AUTH\"\n );\n default:\n throw new Error(\n `Unknown value for data_protection: '${value}'. Valid values: 'complete', 'unlessopen', 'untilfirstauth'`\n );\n }\n case \"icloud\":\n switch (value) {\n case \"xcode6_compatible\":\n return wrap(\"ICLOUD_VERSION\", \"XCODE_6\");\n case \"xcode5_compatible\":\n return wrap(\"ICLOUD_VERSION\", \"XCODE_5\");\n default:\n throw new Error(\n `Unknown value for icloud: '${value}'. Valid values: 'xcode6_compatible', 'xcode5_compatible'`\n );\n }\n case \"game_center\":\n switch (value) {\n case \"mac\":\n return wrap(\"GAME_CENTER_SETTING\", \"GAME_CENTER_MAC\");\n case \"ios\":\n return wrap(\"GAME_CENTER_SETTING\", \"GAME_CENTER_IOS\");\n default:\n throw new Error(\n `Unknown value for game_center: '${value}'. Valid values: 'ios', 'mac'`\n );\n }\n case \"sign_in_with_apple\":\n return wrap(\"APPLE_ID_AUTH_APP_CONSENT\", \"PRIMARY_APP_CONSENT\");\n default:\n return undefined;\n }\n}\n\nexport async function registerBundleId(options: {\n client: AppStoreConnectClient;\n identifier: string;\n name: string;\n platform?: BundleIdPlatform;\n}): Promise<BundleId> {\n // Check if already exists (idempotent)\n const existing = await options.client.bundleIds.find(options.identifier);\n if (existing) return existing;\n\n return options.client.bundleIds.create({\n identifier: options.identifier,\n name: options.name,\n platform: options.platform ?? \"IOS\",\n });\n}\n\nexport async function addCapability(options: {\n client: AppStoreConnectClient;\n bundleIdId: string;\n capabilityType: CapabilityType;\n settings?: CapabilitySettingInput[];\n}): Promise<void> {\n await options.client.capabilities.enable({\n bundleIdId: options.bundleIdId,\n capabilityType: options.capabilityType,\n settings: options.settings,\n });\n}\n\nexport async function removeCapability(options: {\n client: AppStoreConnectClient;\n capabilityId: string;\n}): Promise<void> {\n await options.client.capabilities.disable(options.capabilityId);\n}\n\nexport async function listCapabilities(options: {\n client: AppStoreConnectClient;\n bundleIdId: string;\n}) {\n return options.client.capabilities.listForBundleId(options.bundleIdId);\n}\n\nexport async function enableServices(options: {\n client: AppStoreConnectClient;\n bundleIdId: string;\n /**\n * Service names (Fastlane style, e.g. `data_protection`, `icloud`).\n * Pass either a plain list of names or a record of name → value, where\n * the value either is `true` or one of the per-service variants handled\n * by `buildCapabilitySettings`.\n */\n services: string[] | Record<string, string | boolean>;\n}): Promise<void> {\n const entries: Array<[string, string | boolean]> = Array.isArray(\n options.services\n )\n ? options.services.map((s) => [s, true])\n : Object.entries(options.services);\n\n for (const [service, value] of entries) {\n if (value === false) continue;\n const capType = SERVICE_NAME_TO_CAPABILITY[service];\n if (!capType) continue;\n const settings = buildCapabilitySettings(service, value);\n await addCapability({\n client: options.client,\n bundleIdId: options.bundleIdId,\n capabilityType: capType,\n settings,\n });\n }\n}\n\nexport async function associateAppGroups(options: {\n portalClient: PortalClient;\n bundleIdId: string;\n appGroups: Array<{ name: string; identifier: string }>;\n}): Promise<void> {\n if (!options.appGroups?.length) return;\n\n // Enable the App Groups capability on the App ID once, then associate all\n // requested groups in a single declarative call. Apple's internal group\n // handle comes back under `applicationGroup` (Spaceship's app_group_id) —\n // NOT the human `group.com.…` identifier, which association rejects.\n await options.portalClient.enableAppGroups(options.bundleIdId).catch(() => {});\n\n const existing = await options.portalClient.listAppGroups();\n const appGroupIds: string[] = [];\n for (const group of options.appGroups) {\n let record = existing.find((ag: any) => ag.identifier === group.identifier);\n if (!record) {\n record = await options.portalClient.createAppGroup({\n name: group.name,\n identifier: group.identifier,\n });\n }\n const id =\n record?.applicationGroup ?? record?.applicationGroupId ?? record?.appGroupId ?? record?.id;\n if (id) appGroupIds.push(id);\n }\n\n if (appGroupIds.length) {\n await options.portalClient.assignAppGroups({\n appIdId: options.bundleIdId,\n appGroupIds,\n });\n }\n}\n\nexport async function createApp(options: ProduceOptions): Promise<App> {\n // Check if app already exists\n const existing = await options.client.apps.findByBundleId(options.bundleIdentifier);\n if (existing) return existing;\n\n // Register bundle ID\n const bundleId = await registerBundleId({\n client: options.client,\n identifier: options.bundleIdentifier,\n name: options.appName,\n platform: options.platform,\n });\n\n // Enable services\n if (options.enableServices) {\n for (const service of options.enableServices) {\n await addCapability({\n client: options.client,\n bundleIdId: bundleId.id,\n capabilityType: service,\n });\n }\n }\n\n // Create/associate app groups (requires PortalClient with Apple ID session)\n if (options.appGroups?.length && options.portalClient) {\n await associateAppGroups({\n portalClient: options.portalClient,\n bundleIdId: bundleId.id,\n appGroups: options.appGroups,\n });\n }\n\n // Create app on App Store Connect\n return options.client.apps.create({\n bundleIdentifier: options.bundleIdentifier,\n bundleIdId: bundleId.id,\n appName: options.appName,\n sku: options.sku ?? `${options.bundleIdentifier}.${Date.now()}`,\n primaryLocale: options.primaryLocale,\n });\n}\n"]}
|