@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
package/dist/client/index.cjs
CHANGED
|
@@ -166,6 +166,20 @@ function applePbkdf2(password, salt, iterations, keyLength, protocol) {
|
|
|
166
166
|
|
|
167
167
|
// src/client/apple-session.ts
|
|
168
168
|
var AUTH_BASE = "https://idmsa.apple.com/appleauth/auth";
|
|
169
|
+
async function appleJson(res, what) {
|
|
170
|
+
const text = await res.text();
|
|
171
|
+
try {
|
|
172
|
+
return JSON.parse(text);
|
|
173
|
+
} catch {
|
|
174
|
+
const contentType = (res.headers.get("content-type") ?? "").split(";")[0].trim();
|
|
175
|
+
const title = /<title>([^<]{1,120})<\/title>/i.exec(text)?.[1]?.trim();
|
|
176
|
+
const looksHtml = /^\s*<(!doctype|html)/i.test(text) || contentType === "text/html";
|
|
177
|
+
const page = looksHtml ? "an HTML page" : contentType ? `a ${contentType} response` : "a non-JSON response";
|
|
178
|
+
throw new Error(
|
|
179
|
+
`Apple answered the ${what} with ${page} (HTTP ${res.status}${title ? `, "${title}"` : ""}) instead of JSON. Apple is refusing or rate-limiting sign-ins from this server right now; wait a few minutes and try again. If it keeps happening, sign in once at appleid.apple.com to clear any hold on the account.`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
169
183
|
var OLYMPUS_SESSION = "https://appstoreconnect.apple.com/olympus/v1/session";
|
|
170
184
|
var WIDGET_KEY_URL = "https://appstoreconnect.apple.com/olympus/v1/app/config?hostname=itunesconnect.apple.com";
|
|
171
185
|
var ProgramLicenseAgreementError = class extends Error {
|
|
@@ -252,7 +266,7 @@ async function beginLogin(config) {
|
|
|
252
266
|
}
|
|
253
267
|
async function fetchTwoFactorChallenge(pending) {
|
|
254
268
|
const r = await fetch(`${AUTH_BASE}`, { headers: buildAuthHeadersFromPending(pending) });
|
|
255
|
-
const body = await r
|
|
269
|
+
const body = await appleJson(r, "two-factor challenge");
|
|
256
270
|
const trustedPhoneNumbers = (body.trustedPhoneNumbers ?? []).map((p) => ({
|
|
257
271
|
id: p.id,
|
|
258
272
|
numberWithDialCode: p.numberWithDialCode,
|
|
@@ -273,7 +287,8 @@ async function requestSmsCode(input) {
|
|
|
273
287
|
body: JSON.stringify({ phoneNumber: { id: input.phoneId }, mode: input.mode ?? "sms" })
|
|
274
288
|
});
|
|
275
289
|
}
|
|
276
|
-
async function submitTwoFactorCode(
|
|
290
|
+
async function submitTwoFactorCode(rawInput) {
|
|
291
|
+
const input = { ...rawInput, code: rawInput.code.replace(/[\s\u00a0]+/g, "") };
|
|
277
292
|
const log = input.onLog ?? (() => {
|
|
278
293
|
});
|
|
279
294
|
let path;
|
|
@@ -385,9 +400,12 @@ async function doSirp(user, password, serviceKey, cookieStr, hashcash) {
|
|
|
385
400
|
body: JSON.stringify({ a: aBase64, accountName: user, protocols: ["s2k", "s2k_fo"] }),
|
|
386
401
|
redirect: "manual"
|
|
387
402
|
});
|
|
388
|
-
const initBody = await initRes
|
|
403
|
+
const initBody = await appleJson(initRes, "sign-in init");
|
|
389
404
|
if (initBody.serviceErrors) throw new Error(`Apple auth error: ${JSON.stringify(initBody.serviceErrors)}`);
|
|
390
405
|
const { iteration: iterations, salt: saltB64, b: bB64, c, protocol } = initBody;
|
|
406
|
+
if (!iterations || !saltB64 || !bB64 || !c || !protocol) {
|
|
407
|
+
throw new Error(`Apple's sign-in init answered without a challenge (HTTP ${initRes.status}): ${JSON.stringify(initBody).slice(0, 300)}`);
|
|
408
|
+
}
|
|
391
409
|
const salt = Buffer.from(saltB64, "base64");
|
|
392
410
|
const b = Buffer.from(bB64, "base64");
|
|
393
411
|
const encryptedPassword = applePbkdf2(password, salt, iterations, 32, protocol);
|
|
@@ -430,7 +448,7 @@ async function fetchOlympusSession(session) {
|
|
|
430
448
|
const cookieStr = Object.entries(session.cookies).map(([k, v]) => `${k}=${v}`).join("; ");
|
|
431
449
|
const res = await fetch(OLYMPUS_SESSION, { headers: { Cookie: cookieStr, Accept: "application/json" } });
|
|
432
450
|
if (res.ok) {
|
|
433
|
-
const body = await res
|
|
451
|
+
const body = await appleJson(res, "session lookup");
|
|
434
452
|
if (body?.user?.emailAddress) session.userEmail = body.user.emailAddress;
|
|
435
453
|
if (body?.provider?.providerId) session.teamId = String(body.provider.providerId);
|
|
436
454
|
}
|
|
@@ -442,7 +460,7 @@ async function fetchContractMessages(session) {
|
|
|
442
460
|
headers: { Cookie: cookieStr, Accept: "application/json" }
|
|
443
461
|
});
|
|
444
462
|
if (!res.ok) return [];
|
|
445
|
-
const body = await res
|
|
463
|
+
const body = await appleJson(res, "agreements lookup");
|
|
446
464
|
return (body ?? []).map((m) => ({
|
|
447
465
|
id: m.id ?? "",
|
|
448
466
|
group: m.group ?? "",
|
|
@@ -453,10 +471,23 @@ async function fetchContractMessages(session) {
|
|
|
453
471
|
return [];
|
|
454
472
|
}
|
|
455
473
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
474
|
+
var LOGOUT_URL = "https://appstoreconnect.apple.com/logout";
|
|
475
|
+
function serviceKeyFromLocation(location) {
|
|
476
|
+
if (!location) return null;
|
|
477
|
+
try {
|
|
478
|
+
const key = new URL(location).searchParams.get("widgetKey")?.trim();
|
|
479
|
+
return key && /^[0-9a-f]{16,}$/i.test(key) ? key : null;
|
|
480
|
+
} catch {
|
|
481
|
+
return null;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
async function fetchServiceKey(fetchImpl = fetch) {
|
|
485
|
+
const head = await fetchImpl(LOGOUT_URL, { method: "HEAD", redirect: "manual" });
|
|
486
|
+
const fromRedirect = serviceKeyFromLocation(head.headers.get("location"));
|
|
487
|
+
if (fromRedirect) return fromRedirect;
|
|
488
|
+
const res = await fetchImpl(WIDGET_KEY_URL);
|
|
489
|
+
const body = await appleJson(res, "service key request");
|
|
490
|
+
if (!body?.authServiceKey) throw new Error("Could not fetch Apple service key: the sign-out redirect carried no widgetKey and the config endpoint had no authServiceKey.");
|
|
460
491
|
return body.authServiceKey;
|
|
461
492
|
}
|
|
462
493
|
function buildAuthHeaders(session) {
|
|
@@ -982,6 +1013,43 @@ var AppsResource = class {
|
|
|
982
1013
|
});
|
|
983
1014
|
return results[0] ?? null;
|
|
984
1015
|
}
|
|
1016
|
+
/**
|
|
1017
|
+
* Create an App Store Connect **app record** (the thing that shows up
|
|
1018
|
+
* under "My Apps" and that TestFlight / App Store uploads require).
|
|
1019
|
+
*
|
|
1020
|
+
* This is distinct from registering an App ID in the Developer Portal —
|
|
1021
|
+
* you need BOTH. The Developer Portal App ID unlocks provisioning
|
|
1022
|
+
* profiles and entitlements; the App Store Connect app record unlocks
|
|
1023
|
+
* uploads. `upload_to_testflight` fails with "Couldn't find app
|
|
1024
|
+
* 'com.foo.bar' on the account…" when this record is missing.
|
|
1025
|
+
*
|
|
1026
|
+
* `bundleIdId` is the REST API primary key of the bundle id resource
|
|
1027
|
+
* (not the identifier string) — fetch it via `bundleIds.find(identifier)`
|
|
1028
|
+
* or from the response of `bundleIds.create()`.
|
|
1029
|
+
*
|
|
1030
|
+
* `sku` is an arbitrary unique string Apple uses to identify the app in
|
|
1031
|
+
* their internal records. If you don't have a meaningful one, pass the
|
|
1032
|
+
* bundle identifier itself or append a timestamp for uniqueness.
|
|
1033
|
+
*/
|
|
1034
|
+
async create(params) {
|
|
1035
|
+
const response = await this.http.post("/v1/apps", {
|
|
1036
|
+
data: {
|
|
1037
|
+
type: "apps",
|
|
1038
|
+
attributes: {
|
|
1039
|
+
bundleId: params.bundleIdentifier,
|
|
1040
|
+
name: params.appName,
|
|
1041
|
+
sku: params.sku,
|
|
1042
|
+
primaryLocale: params.primaryLocale ?? "en-US"
|
|
1043
|
+
},
|
|
1044
|
+
relationships: {
|
|
1045
|
+
bundleId: {
|
|
1046
|
+
data: { type: "bundleIds", id: params.bundleIdId }
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
});
|
|
1051
|
+
return response.data;
|
|
1052
|
+
}
|
|
985
1053
|
};
|
|
986
1054
|
|
|
987
1055
|
// src/resources/builds.ts
|
|
@@ -2017,6 +2085,19 @@ var PreReleaseVersionsResource = class {
|
|
|
2017
2085
|
};
|
|
2018
2086
|
|
|
2019
2087
|
// src/resources/review-submission-items.ts
|
|
2088
|
+
var ITEM_RELATIONSHIPS = {
|
|
2089
|
+
appStoreVersionId: ["appStoreVersion", "appStoreVersions"],
|
|
2090
|
+
appCustomProductPageVersionId: ["appCustomProductPageVersion", "appCustomProductPageVersions"],
|
|
2091
|
+
appStoreVersionExperimentId: ["appStoreVersionExperiment", "appStoreVersionExperiments"],
|
|
2092
|
+
appStoreVersionExperimentV2Id: ["appStoreVersionExperimentV2", "appStoreVersionExperiments"],
|
|
2093
|
+
appEventId: ["appEvent", "appEvents"],
|
|
2094
|
+
appAssetLibraryImageId: ["appAssetLibraryImage", "appAssetLibraryImages"],
|
|
2095
|
+
appAssetLibraryVideoId: ["appAssetLibraryVideo", "appAssetLibraryVideos"],
|
|
2096
|
+
backgroundAssetVersionId: ["backgroundAssetVersion", "backgroundAssetVersions"],
|
|
2097
|
+
inAppPurchaseVersionId: ["inAppPurchaseVersion", "inAppPurchaseVersions"],
|
|
2098
|
+
subscriptionVersionId: ["subscriptionVersion", "subscriptionVersions"],
|
|
2099
|
+
subscriptionGroupVersionId: ["subscriptionGroupVersion", "subscriptionGroupVersions"]
|
|
2100
|
+
};
|
|
2020
2101
|
var ReviewSubmissionItemsResource = class {
|
|
2021
2102
|
constructor(http) {
|
|
2022
2103
|
this.http = http;
|
|
@@ -2038,32 +2119,20 @@ var ReviewSubmissionItemsResource = class {
|
|
|
2038
2119
|
);
|
|
2039
2120
|
return response.data;
|
|
2040
2121
|
}
|
|
2122
|
+
/**
|
|
2123
|
+
* Add one item to a review submission. Besides versions, asset library
|
|
2124
|
+
* images and videos can be submitted on their own (ASC API 4.5.1) so
|
|
2125
|
+
* creative assets are approved ahead of a campaign.
|
|
2126
|
+
*/
|
|
2041
2127
|
async create(params) {
|
|
2042
2128
|
const relationships = {
|
|
2043
2129
|
reviewSubmission: {
|
|
2044
2130
|
data: { type: "reviewSubmissions", id: params.reviewSubmissionId }
|
|
2045
2131
|
}
|
|
2046
2132
|
};
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
};
|
|
2051
|
-
}
|
|
2052
|
-
if (params.appCustomProductPageVersionId) {
|
|
2053
|
-
relationships.appCustomProductPageVersion = {
|
|
2054
|
-
data: {
|
|
2055
|
-
type: "appCustomProductPageVersions",
|
|
2056
|
-
id: params.appCustomProductPageVersionId
|
|
2057
|
-
}
|
|
2058
|
-
};
|
|
2059
|
-
}
|
|
2060
|
-
if (params.appStoreVersionExperimentId) {
|
|
2061
|
-
relationships.appStoreVersionExperiment = {
|
|
2062
|
-
data: {
|
|
2063
|
-
type: "appStoreVersionExperiments",
|
|
2064
|
-
id: params.appStoreVersionExperimentId
|
|
2065
|
-
}
|
|
2066
|
-
};
|
|
2133
|
+
for (const [param, [relationship, type]] of Object.entries(ITEM_RELATIONSHIPS)) {
|
|
2134
|
+
const id = params[param];
|
|
2135
|
+
if (id) relationships[relationship] = { data: { type, id } };
|
|
2067
2136
|
}
|
|
2068
2137
|
const response = await this.http.post(
|
|
2069
2138
|
"/v1/reviewSubmissionItems",
|
|
@@ -2267,6 +2336,189 @@ var XcodeMetricsResource = class {
|
|
|
2267
2336
|
}
|
|
2268
2337
|
};
|
|
2269
2338
|
|
|
2339
|
+
// src/resources/app-asset-libraries.ts
|
|
2340
|
+
var AppAssetLibrariesResource = class {
|
|
2341
|
+
constructor(http) {
|
|
2342
|
+
this.http = http;
|
|
2343
|
+
}
|
|
2344
|
+
http;
|
|
2345
|
+
async getForApp(appId) {
|
|
2346
|
+
const response = await this.http.get(
|
|
2347
|
+
`/v1/apps/${appId}/assetLibrary`
|
|
2348
|
+
);
|
|
2349
|
+
return response.data;
|
|
2350
|
+
}
|
|
2351
|
+
async listImages(libraryId, params = {}) {
|
|
2352
|
+
return this.http.all(`/v1/appAssetLibraries/${libraryId}/images`, params);
|
|
2353
|
+
}
|
|
2354
|
+
async listVideos(libraryId, params = {}) {
|
|
2355
|
+
return this.http.all(`/v1/appAssetLibraries/${libraryId}/videos`, params);
|
|
2356
|
+
}
|
|
2357
|
+
/**
|
|
2358
|
+
* Specs, placement groups and limits. Apple adds placement groups (new
|
|
2359
|
+
* devices) without an API version bump, so read them from here rather than
|
|
2360
|
+
* hard-coding display types.
|
|
2361
|
+
*/
|
|
2362
|
+
async refData(params = {}) {
|
|
2363
|
+
const filter = {};
|
|
2364
|
+
if (params.features?.length) filter.features = params.features;
|
|
2365
|
+
if (params.placementTypes?.length) filter.placementTypes = params.placementTypes;
|
|
2366
|
+
if (params.placementProfileGroups?.length) filter.placementProfileGroups = params.placementProfileGroups;
|
|
2367
|
+
const data = await this.http.all("/v1/appAssetLibraryRefData", { filter });
|
|
2368
|
+
return mergeRefData(data.map((d) => d.attributes));
|
|
2369
|
+
}
|
|
2370
|
+
};
|
|
2371
|
+
function mergeRefData(parts) {
|
|
2372
|
+
const merged = {
|
|
2373
|
+
features: [],
|
|
2374
|
+
placementProfileGroups: [],
|
|
2375
|
+
imageSpecs: [],
|
|
2376
|
+
videoSpecs: [],
|
|
2377
|
+
placementTypes: [],
|
|
2378
|
+
displayClasses: []
|
|
2379
|
+
};
|
|
2380
|
+
for (const part of parts) {
|
|
2381
|
+
for (const key of Object.keys(merged)) {
|
|
2382
|
+
merged[key].push(...part[key] ?? []);
|
|
2383
|
+
}
|
|
2384
|
+
}
|
|
2385
|
+
return merged;
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
// src/resources/app-asset-library-assets.ts
|
|
2389
|
+
var AssetLibraryMediaResource = class {
|
|
2390
|
+
constructor(http) {
|
|
2391
|
+
this.http = http;
|
|
2392
|
+
}
|
|
2393
|
+
http;
|
|
2394
|
+
async get(id) {
|
|
2395
|
+
const response = await this.http.get(`/v1/${this.type}/${id}`);
|
|
2396
|
+
return response.data;
|
|
2397
|
+
}
|
|
2398
|
+
async reserve(params, extra = {}) {
|
|
2399
|
+
const { libraryId, ...attributes } = params;
|
|
2400
|
+
const response = await this.http.post(`/v1/${this.type}`, {
|
|
2401
|
+
data: {
|
|
2402
|
+
type: this.type,
|
|
2403
|
+
attributes: { ...attributes, ...extra },
|
|
2404
|
+
relationships: {
|
|
2405
|
+
assetLibrary: { data: { type: "appAssetLibraries", id: libraryId } }
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2408
|
+
});
|
|
2409
|
+
return response.data;
|
|
2410
|
+
}
|
|
2411
|
+
async patch(id, attributes) {
|
|
2412
|
+
const response = await this.http.patch(`/v1/${this.type}/${id}`, {
|
|
2413
|
+
data: { type: this.type, id, attributes }
|
|
2414
|
+
});
|
|
2415
|
+
return response.data;
|
|
2416
|
+
}
|
|
2417
|
+
/** Fails with 409 STATE_ERROR.ASSET_HAS_PLACEMENTS while the asset is still placed. */
|
|
2418
|
+
async delete(id) {
|
|
2419
|
+
await this.http.delete(`/v1/${this.type}/${id}`);
|
|
2420
|
+
}
|
|
2421
|
+
async listPlacements(id, params = {}) {
|
|
2422
|
+
return this.http.all(`/v1/${this.type}/${id}/placements`, params);
|
|
2423
|
+
}
|
|
2424
|
+
};
|
|
2425
|
+
var AppAssetLibraryImagesResource = class extends AssetLibraryMediaResource {
|
|
2426
|
+
type = "appAssetLibraryImages";
|
|
2427
|
+
async create(params) {
|
|
2428
|
+
return this.reserve(params);
|
|
2429
|
+
}
|
|
2430
|
+
async update(id, attributes) {
|
|
2431
|
+
return this.patch(id, { ...attributes });
|
|
2432
|
+
}
|
|
2433
|
+
};
|
|
2434
|
+
var AppAssetLibraryVideosResource = class extends AssetLibraryMediaResource {
|
|
2435
|
+
type = "appAssetLibraryVideos";
|
|
2436
|
+
async create(params) {
|
|
2437
|
+
const { previewFrameTimeCode, ...rest } = params;
|
|
2438
|
+
return this.reserve(rest, previewFrameTimeCode ? { previewFrameTimeCode } : {});
|
|
2439
|
+
}
|
|
2440
|
+
async update(id, attributes) {
|
|
2441
|
+
return this.patch(id, { ...attributes });
|
|
2442
|
+
}
|
|
2443
|
+
};
|
|
2444
|
+
|
|
2445
|
+
// src/resources/app-asset-library-placements.ts
|
|
2446
|
+
var TARGET_TYPES = {
|
|
2447
|
+
appStoreVersionLocalization: "appStoreVersionLocalizations",
|
|
2448
|
+
appCustomProductPageLocalization: "appCustomProductPageLocalizations",
|
|
2449
|
+
appEventLocalization: "appEventLocalizations",
|
|
2450
|
+
appStoreVersionExperimentTreatmentLocalization: "appStoreVersionExperimentTreatmentLocalizations"
|
|
2451
|
+
};
|
|
2452
|
+
function targetRelationship(target) {
|
|
2453
|
+
return { [target.kind]: { data: { type: TARGET_TYPES[target.kind], id: target.id } } };
|
|
2454
|
+
}
|
|
2455
|
+
var AppAssetLibraryPlacementsResource = class {
|
|
2456
|
+
constructor(http) {
|
|
2457
|
+
this.http = http;
|
|
2458
|
+
}
|
|
2459
|
+
http;
|
|
2460
|
+
/**
|
|
2461
|
+
* Place an image or video on one localization. Placements cannot be edited —
|
|
2462
|
+
* delete and recreate. The parent version/page must be editable.
|
|
2463
|
+
*/
|
|
2464
|
+
async create(params) {
|
|
2465
|
+
if (!params.imageId === !params.videoId) {
|
|
2466
|
+
throw new Error("A placement needs exactly one of imageId or videoId");
|
|
2467
|
+
}
|
|
2468
|
+
const media = params.imageId ? { image: { data: { type: "appAssetLibraryImages", id: params.imageId } } } : { video: { data: { type: "appAssetLibraryVideos", id: params.videoId } } };
|
|
2469
|
+
const response = await this.http.post(
|
|
2470
|
+
"/v1/appAssetLibraryPlacements",
|
|
2471
|
+
{
|
|
2472
|
+
data: {
|
|
2473
|
+
type: "appAssetLibraryPlacements",
|
|
2474
|
+
attributes: { placementType: params.placementType, placementGroup: params.placementGroup },
|
|
2475
|
+
relationships: { ...media, ...targetRelationship(params.target) }
|
|
2476
|
+
}
|
|
2477
|
+
}
|
|
2478
|
+
);
|
|
2479
|
+
return response.data;
|
|
2480
|
+
}
|
|
2481
|
+
async get(id, params = {}) {
|
|
2482
|
+
const response = await this.http.get(
|
|
2483
|
+
`/v1/appAssetLibraryPlacements/${id}`,
|
|
2484
|
+
params.include ? { include: params.include } : void 0
|
|
2485
|
+
);
|
|
2486
|
+
return response.data;
|
|
2487
|
+
}
|
|
2488
|
+
async delete(id) {
|
|
2489
|
+
await this.http.delete(`/v1/appAssetLibraryPlacements/${id}`);
|
|
2490
|
+
}
|
|
2491
|
+
/** Placements on one localization, in display order by default. */
|
|
2492
|
+
async listForTarget(target, params = {}) {
|
|
2493
|
+
const filter = {};
|
|
2494
|
+
if (params.placementType) filter.placementType = params.placementType;
|
|
2495
|
+
if (params.placementGroup) filter.placementGroup = params.placementGroup;
|
|
2496
|
+
const listParams = { filter, include: params.include, sort: "placementGroupPosition" };
|
|
2497
|
+
return this.http.all(
|
|
2498
|
+
`/v1/${TARGET_TYPES[target.kind]}/${target.id}/placements`,
|
|
2499
|
+
listParams
|
|
2500
|
+
);
|
|
2501
|
+
}
|
|
2502
|
+
/** Set the display order of a placement group. In-app event localizations cannot be ordered. */
|
|
2503
|
+
async order(params) {
|
|
2504
|
+
if (params.target.kind === "appEventLocalization") {
|
|
2505
|
+
throw new Error("In-app event placements cannot be ordered");
|
|
2506
|
+
}
|
|
2507
|
+
await this.http.post("/v1/appAssetLibraryPlacementOrderingRequests", {
|
|
2508
|
+
data: {
|
|
2509
|
+
type: "appAssetLibraryPlacementOrderingRequests",
|
|
2510
|
+
attributes: { placementGroup: params.placementGroup },
|
|
2511
|
+
relationships: {
|
|
2512
|
+
orderedPlacements: {
|
|
2513
|
+
data: params.placementIds.map((id) => ({ type: "appAssetLibraryPlacements", id }))
|
|
2514
|
+
},
|
|
2515
|
+
...targetRelationship(params.target)
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
});
|
|
2519
|
+
}
|
|
2520
|
+
};
|
|
2521
|
+
|
|
2270
2522
|
// src/client/portal.ts
|
|
2271
2523
|
var PORTAL_BASE = "https://developer.apple.com/services-account/QH65B2";
|
|
2272
2524
|
function pickUniqueKeyName(base, taken) {
|
|
@@ -2602,7 +2854,10 @@ var PortalClient = class _PortalClient {
|
|
|
2602
2854
|
}
|
|
2603
2855
|
// ── Teams ──────────────────────────────────────────────────────────────
|
|
2604
2856
|
async listTeams() {
|
|
2605
|
-
const data = await this.post("account/listTeams.action", {
|
|
2857
|
+
const data = await this.post("account/listTeams.action", {
|
|
2858
|
+
pageSize: "500",
|
|
2859
|
+
pageNumber: "1"
|
|
2860
|
+
});
|
|
2606
2861
|
return data.teams ?? [];
|
|
2607
2862
|
}
|
|
2608
2863
|
// ── App IDs / Bundle IDs ───────────────────────────────────────────────
|
|
@@ -2616,11 +2871,12 @@ var PortalClient = class _PortalClient {
|
|
|
2616
2871
|
return data.appIds ?? [];
|
|
2617
2872
|
}
|
|
2618
2873
|
async createAppId(params) {
|
|
2874
|
+
const safeName = params.name.replace(/[^0-9A-Za-z\s]/g, " ").replace(/\s+/g, " ").trim() || "App";
|
|
2619
2875
|
const reqParams = {
|
|
2620
2876
|
teamId: this.teamId,
|
|
2621
2877
|
type: "explicit",
|
|
2622
2878
|
identifier: params.identifier,
|
|
2623
|
-
name:
|
|
2879
|
+
name: safeName
|
|
2624
2880
|
};
|
|
2625
2881
|
if (params.enablePush) reqParams.push = "on";
|
|
2626
2882
|
if (params.enableIAP !== false) reqParams.inAppPurchase = "on";
|
|
@@ -2655,6 +2911,191 @@ var PortalClient = class _PortalClient {
|
|
|
2655
2911
|
featureValue: params.enabled ? "on" : "off"
|
|
2656
2912
|
});
|
|
2657
2913
|
}
|
|
2914
|
+
// ── Application Groups ──────────────────────────────────────────────────
|
|
2915
|
+
//
|
|
2916
|
+
// App Groups (e.g. `group.com.playspina.com`) are the only clean way to
|
|
2917
|
+
// share data — an auth token, in our case — between a host app and an
|
|
2918
|
+
// embedded extension (Messages / Notification Service / etc.). App Store
|
|
2919
|
+
// Connect API keys (.p8) genuinely cannot manage them; Apple only exposes
|
|
2920
|
+
// group create/associate through this legacy session-cookie portal API,
|
|
2921
|
+
// which is why they live on PortalClient (Apple ID session) and not on the
|
|
2922
|
+
// ASC REST client. Endpoint shapes ported 1:1 from Spaceship's
|
|
2923
|
+
// portal_client.rb (listApplicationGroups / addApplicationGroup /
|
|
2924
|
+
// assignApplicationGroupToAppId).
|
|
2925
|
+
/** Apple's internal feature code for the App Groups capability. */
|
|
2926
|
+
static APP_GROUPS_FEATURE = "APG3427HIY";
|
|
2927
|
+
/** List all app groups in the team. */
|
|
2928
|
+
async listAppGroups() {
|
|
2929
|
+
const data = await this.post("account/ios/identifiers/listApplicationGroups.action", {
|
|
2930
|
+
teamId: this.teamId,
|
|
2931
|
+
pageNumber: "1",
|
|
2932
|
+
pageSize: "500",
|
|
2933
|
+
sort: "name=asc"
|
|
2934
|
+
});
|
|
2935
|
+
return data.applicationGroupList ?? [];
|
|
2936
|
+
}
|
|
2937
|
+
/**
|
|
2938
|
+
* Create an app group, returning the raw group record. Idempotent —
|
|
2939
|
+
* Apple rejects a duplicate group identifier ("Multiple App Groups may
|
|
2940
|
+
* not have the same identifier"), so we list first and reuse an existing
|
|
2941
|
+
* group when the identifier already exists in the team.
|
|
2942
|
+
*
|
|
2943
|
+
* Note the two ids on the returned record: `identifier` is the
|
|
2944
|
+
* `group.com.…` string you type, while `applicationGroup` is Apple's
|
|
2945
|
+
* opaque internal handle that association actually requires — do NOT pass
|
|
2946
|
+
* the human identifier to assignAppGroups.
|
|
2947
|
+
*/
|
|
2948
|
+
async createAppGroup(params) {
|
|
2949
|
+
const existing = await this.listAppGroups();
|
|
2950
|
+
const hit = existing.find((g) => g.identifier === params.identifier);
|
|
2951
|
+
if (hit) return hit;
|
|
2952
|
+
const safeName = params.name.replace(/[^0-9A-Za-z\s]/g, " ").replace(/\s+/g, " ").trim() || "App Group";
|
|
2953
|
+
const data = await this.post("account/ios/identifiers/addApplicationGroup.action", {
|
|
2954
|
+
teamId: this.teamId,
|
|
2955
|
+
identifier: params.identifier,
|
|
2956
|
+
name: safeName
|
|
2957
|
+
});
|
|
2958
|
+
return data.applicationGroup;
|
|
2959
|
+
}
|
|
2960
|
+
/**
|
|
2961
|
+
* Enable the App Groups capability on an App ID. Required before an
|
|
2962
|
+
* App ID can have a group associated with it — mirrors Spaceship
|
|
2963
|
+
* enabling `AppService::AppGroup` before `associate_groups`.
|
|
2964
|
+
*/
|
|
2965
|
+
async enableAppGroups(appIdId) {
|
|
2966
|
+
await this.post("account/ios/identifiers/updateService.action", {
|
|
2967
|
+
teamId: this.teamId,
|
|
2968
|
+
displayId: appIdId,
|
|
2969
|
+
featureType: _PortalClient.APP_GROUPS_FEATURE,
|
|
2970
|
+
featureValue: "true"
|
|
2971
|
+
});
|
|
2972
|
+
}
|
|
2973
|
+
/**
|
|
2974
|
+
* Associate one or more app groups with an App ID. `appGroupIds` are the
|
|
2975
|
+
* internal ids (Spaceship's `app_group_id`), NOT the `group.com.…`
|
|
2976
|
+
* identifiers. Apple wants both `appIdId` and `displayId` set to the
|
|
2977
|
+
* App ID's internal id, per Spaceship's associate_groups_with_app.
|
|
2978
|
+
*/
|
|
2979
|
+
async assignAppGroups(params) {
|
|
2980
|
+
await this.post("account/ios/identifiers/assignApplicationGroupToAppId.action", {
|
|
2981
|
+
teamId: this.teamId,
|
|
2982
|
+
appIdId: params.appIdId,
|
|
2983
|
+
displayId: params.appIdId,
|
|
2984
|
+
applicationGroups: params.appGroupIds
|
|
2985
|
+
});
|
|
2986
|
+
}
|
|
2987
|
+
// ── Apple Pay merchants (OMCs) ─────────────────────────────────────────
|
|
2988
|
+
//
|
|
2989
|
+
// Merchant IDs are team-level identifiers (merchant.com.…) that an App ID's
|
|
2990
|
+
// Apple Pay capability must be LINKED to — enabling the capability alone
|
|
2991
|
+
// produces profiles that fail with "doesn't support the … Merchant ID".
|
|
2992
|
+
// Like App Groups, merchants are only manageable through the legacy
|
|
2993
|
+
// session-cookie portal API. Endpoint shapes ported 1:1 from Spaceship's
|
|
2994
|
+
// portal_client.rb (merchants / create_merchant! /
|
|
2995
|
+
// associate_merchants_with_app).
|
|
2996
|
+
/** Apple's internal feature code for the Apple Pay capability. */
|
|
2997
|
+
static APPLE_PAY_FEATURE = "OM633U5T5G";
|
|
2998
|
+
/**
|
|
2999
|
+
* List all Apple Pay merchant IDs in the team. Each record maps
|
|
3000
|
+
* (per Spaceship's merchant.rb attr_mapping): `omcId` = internal id,
|
|
3001
|
+
* `identifier` = the human `merchant.com.…` string, `name` = display name.
|
|
3002
|
+
*/
|
|
3003
|
+
async listMerchants() {
|
|
3004
|
+
const data = await this.post("account/ios/identifiers/listOMCs.action", {
|
|
3005
|
+
teamId: this.teamId,
|
|
3006
|
+
pageNumber: "1",
|
|
3007
|
+
pageSize: "500",
|
|
3008
|
+
sort: "name=asc"
|
|
3009
|
+
});
|
|
3010
|
+
return data.identifierList ?? [];
|
|
3011
|
+
}
|
|
3012
|
+
/**
|
|
3013
|
+
* Register (or reuse) a merchant ID, returning its INTERNAL id (`omcId`) —
|
|
3014
|
+
* Apple's opaque handle that association requires, NOT the human
|
|
3015
|
+
* `merchant.com.…` identifier. Idempotent: lists first and reuses an
|
|
3016
|
+
* existing merchant with the same identifier. Endpoint + params ported 1:1
|
|
3017
|
+
* from Spaceship's create_merchant! (addOMC.action).
|
|
3018
|
+
*/
|
|
3019
|
+
async createMerchant(params) {
|
|
3020
|
+
const existing = await this.listMerchants();
|
|
3021
|
+
const hit = existing.find((m) => m.identifier === params.identifier);
|
|
3022
|
+
if (hit?.omcId) return String(hit.omcId);
|
|
3023
|
+
const safeName = params.name.replace(/[^0-9A-Za-z\s]/g, " ").replace(/\s+/g, " ").trim() || "Merchant";
|
|
3024
|
+
const data = await this.post("account/ios/identifiers/addOMC.action", {
|
|
3025
|
+
name: safeName,
|
|
3026
|
+
identifier: params.identifier,
|
|
3027
|
+
teamId: this.teamId
|
|
3028
|
+
});
|
|
3029
|
+
const rec = data.omcId ?? data;
|
|
3030
|
+
const id = typeof rec === "string" ? rec : rec?.omcId ?? rec?.merchantId;
|
|
3031
|
+
if (!id) {
|
|
3032
|
+
throw new Error("Apple returned no internal merchant id (omcId) for the registered merchant.");
|
|
3033
|
+
}
|
|
3034
|
+
return String(id);
|
|
3035
|
+
}
|
|
3036
|
+
/**
|
|
3037
|
+
* Enable the Apple Pay capability on an App ID. Apple Pay is a standard
|
|
3038
|
+
* AppService (service_id OM633U5T5G) whose service_uri is the default
|
|
3039
|
+
* `updateService.action` — confirmed in Spaceship's app_service.rb.
|
|
3040
|
+
*/
|
|
3041
|
+
async enableApplePay(appIdId) {
|
|
3042
|
+
await this.post("account/ios/identifiers/updateService.action", {
|
|
3043
|
+
teamId: this.teamId,
|
|
3044
|
+
displayId: appIdId,
|
|
3045
|
+
featureType: _PortalClient.APPLE_PAY_FEATURE,
|
|
3046
|
+
featureValue: "true"
|
|
3047
|
+
});
|
|
3048
|
+
}
|
|
3049
|
+
/**
|
|
3050
|
+
* Associate merchant IDs with an App ID's Apple Pay capability. `omcIds`
|
|
3051
|
+
* are the internal ids (each merchant record's `omcId`), NOT the
|
|
3052
|
+
* `merchant.com.…` identifiers. Endpoint + params ported 1:1 from
|
|
3053
|
+
* Spaceship's associate_merchants_with_app (assignOMCToAppId.action — note
|
|
3054
|
+
* the singular "OMC", and NO displayId param).
|
|
3055
|
+
*/
|
|
3056
|
+
async assignMerchants(params) {
|
|
3057
|
+
await this.post("account/ios/identifiers/assignOMCToAppId.action", {
|
|
3058
|
+
teamId: this.teamId,
|
|
3059
|
+
appIdId: params.appIdId,
|
|
3060
|
+
omcIds: params.omcIds
|
|
3061
|
+
});
|
|
3062
|
+
}
|
|
3063
|
+
/**
|
|
3064
|
+
* Create an Apple Pay **Payment Processing Certificate** on a merchant ID
|
|
3065
|
+
* from a CSR — the certificate a PSP (e.g. Stripe) hands you as a CSR, which
|
|
3066
|
+
* must be uploaded to the Merchant ID in Apple Developer, then the resulting
|
|
3067
|
+
* `.cer` downloaded and given back to the PSP so it can decrypt payment
|
|
3068
|
+
* tokens. This is the one manual Apple-portal step in wiring up Apple Pay.
|
|
3069
|
+
*
|
|
3070
|
+
* Ported 1:1 from Spaceship's create_certificate! (submitCertificateRequest
|
|
3071
|
+
* .action): the merchant's INTERNAL id (`omcId`) is passed as BOTH `appIdId`
|
|
3072
|
+
* and `specialIdentifierDisplayId` — the latter is how the portal scopes a
|
|
3073
|
+
* cert to a merchant/special identifier rather than an App ID. The cert type
|
|
3074
|
+
* is APPLE_PAY (`4APLUP237T`). Returns the created certRequest (its
|
|
3075
|
+
* `certificateId` feeds `downloadApplePayCertificate`).
|
|
3076
|
+
*
|
|
3077
|
+
* @param omcId the merchant's internal id (from createMerchant/listMerchants)
|
|
3078
|
+
* @param csrContent the PEM CSR string (Stripe's "Apple Pay CSR")
|
|
3079
|
+
*/
|
|
3080
|
+
async createApplePayCertificate(params) {
|
|
3081
|
+
const data = await this.post("account/ios/certificate/submitCertificateRequest.action", {
|
|
3082
|
+
teamId: this.teamId,
|
|
3083
|
+
type: _PortalClient.CERT_TYPES.APPLE_PAY,
|
|
3084
|
+
csrContent: params.csrContent,
|
|
3085
|
+
appIdId: params.omcId,
|
|
3086
|
+
specialIdentifierDisplayId: params.omcId
|
|
3087
|
+
});
|
|
3088
|
+
return data.certRequest;
|
|
3089
|
+
}
|
|
3090
|
+
/**
|
|
3091
|
+
* Download an Apple Pay Payment Processing Certificate's raw bytes by its
|
|
3092
|
+
* certificate id (from `createApplePayCertificate`). Thin wrapper over
|
|
3093
|
+
* `downloadCertificate` pinned to the APPLE_PAY type — the DER `.cer` you
|
|
3094
|
+
* upload back into Stripe.
|
|
3095
|
+
*/
|
|
3096
|
+
async downloadApplePayCertificate(certificateId) {
|
|
3097
|
+
return this.downloadCertificate(certificateId, _PortalClient.CERT_TYPES.APPLE_PAY);
|
|
3098
|
+
}
|
|
2658
3099
|
// ── Certificates ───────────────────────────────────────────────────────
|
|
2659
3100
|
async listCertificates(types) {
|
|
2660
3101
|
const iosTypes = types ?? [
|
|
@@ -3167,6 +3608,10 @@ var AppStoreConnectClient = class {
|
|
|
3167
3608
|
inAppPurchases;
|
|
3168
3609
|
gameCenterDetail;
|
|
3169
3610
|
xcodeMetrics;
|
|
3611
|
+
appAssetLibraries;
|
|
3612
|
+
appAssetLibraryImages;
|
|
3613
|
+
appAssetLibraryVideos;
|
|
3614
|
+
appAssetLibraryPlacements;
|
|
3170
3615
|
constructor(config) {
|
|
3171
3616
|
const tokenManager = new TokenManager({
|
|
3172
3617
|
keyId: config.keyId,
|
|
@@ -3210,6 +3655,10 @@ var AppStoreConnectClient = class {
|
|
|
3210
3655
|
this.inAppPurchases = new InAppPurchasesResource(this.http);
|
|
3211
3656
|
this.gameCenterDetail = new GameCenterDetailResource(this.http);
|
|
3212
3657
|
this.xcodeMetrics = new XcodeMetricsResource(this.http);
|
|
3658
|
+
this.appAssetLibraries = new AppAssetLibrariesResource(this.http);
|
|
3659
|
+
this.appAssetLibraryImages = new AppAssetLibraryImagesResource(this.http);
|
|
3660
|
+
this.appAssetLibraryVideos = new AppAssetLibraryVideosResource(this.http);
|
|
3661
|
+
this.appAssetLibraryPlacements = new AppAssetLibraryPlacementsResource(this.http);
|
|
3213
3662
|
}
|
|
3214
3663
|
async request(path, options) {
|
|
3215
3664
|
return this.http.request(path, options);
|