@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/deliver/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn } from 'child_process';
|
|
2
2
|
import { mkdtemp, writeFile, unlink, readFile, stat, readdir } from 'fs/promises';
|
|
3
|
-
import { join, extname } from 'path';
|
|
3
|
+
import { join, basename, extname, relative } from 'path';
|
|
4
4
|
import { tmpdir } from 'os';
|
|
5
5
|
import { existsSync } from 'fs';
|
|
6
6
|
import { createHash } from 'crypto';
|
|
@@ -164,6 +164,306 @@ async function loadMetadata(metadataPath) {
|
|
|
164
164
|
}
|
|
165
165
|
return { localizations, copyright, reviewInfo, reviewInformation };
|
|
166
166
|
}
|
|
167
|
+
var ASSET_FOLDERS = {
|
|
168
|
+
screenshots: "APP_SCREENSHOT",
|
|
169
|
+
imessage_screenshots: "IMESSAGE_APP_SCREENSHOT",
|
|
170
|
+
previews: "APP_PREVIEW",
|
|
171
|
+
header: "PRODUCT_PAGE_HEADER_ASSET",
|
|
172
|
+
search_results: "APP_STORE_SEARCH_RESULTS_ASSET",
|
|
173
|
+
event_card: "EVENT_CARD_ASSET",
|
|
174
|
+
event_details: "EVENT_DETAILS_PAGE_ASSET"
|
|
175
|
+
};
|
|
176
|
+
var IMAGE_EXTENSIONS = [".png", ".jpg", ".jpeg"];
|
|
177
|
+
var VIDEO_EXTENSIONS = [".mp4", ".mov", ".m4v"];
|
|
178
|
+
var READY_STATES = [
|
|
179
|
+
"COMPLETE",
|
|
180
|
+
"PREPARE_FOR_SUBMISSION",
|
|
181
|
+
"READY_FOR_REVIEW",
|
|
182
|
+
"WAITING_FOR_REVIEW",
|
|
183
|
+
"IN_REVIEW",
|
|
184
|
+
"ACCEPTED",
|
|
185
|
+
"APPROVED"
|
|
186
|
+
];
|
|
187
|
+
function categoryFor(placementType) {
|
|
188
|
+
return placementType === "APP_SCREENSHOT" || placementType === "IMESSAGE_APP_SCREENSHOT" || placementType === "APP_PREVIEW" ? "APP_SCREENSHOTS_AND_PREVIEWS" : "CREATIVE_ASSETS";
|
|
189
|
+
}
|
|
190
|
+
function readImageSize(data) {
|
|
191
|
+
if (data.length >= 26 && data.readUInt32BE(0) === 2303741511) {
|
|
192
|
+
const colorType = data[25];
|
|
193
|
+
return {
|
|
194
|
+
width: data.readUInt32BE(16),
|
|
195
|
+
height: data.readUInt32BE(20),
|
|
196
|
+
alpha: colorType === 4 || colorType === 6
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
if (data.length >= 4 && data[0] === 255 && data[1] === 216) {
|
|
200
|
+
let offset = 2;
|
|
201
|
+
while (offset + 9 < data.length) {
|
|
202
|
+
if (data[offset] !== 255) return null;
|
|
203
|
+
const marker = data[offset + 1];
|
|
204
|
+
const length = data.readUInt16BE(offset + 2);
|
|
205
|
+
const isSof = marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204;
|
|
206
|
+
if (isSof) {
|
|
207
|
+
return { height: data.readUInt16BE(offset + 5), width: data.readUInt16BE(offset + 7), alpha: false };
|
|
208
|
+
}
|
|
209
|
+
offset += 2 + length;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
function fits(spec, width, height) {
|
|
215
|
+
const d = spec.dimensions;
|
|
216
|
+
return width >= d.minWidth && width <= d.maxWidth && height >= d.minHeight && height <= d.maxHeight;
|
|
217
|
+
}
|
|
218
|
+
function groupsForFeature(refData, feature, placementType) {
|
|
219
|
+
const mappings = refData.placementTypes?.find((p) => p.placementTypeId === placementType)?.specMappings ?? [];
|
|
220
|
+
const all = mappings.map((m) => m.placementGroupId);
|
|
221
|
+
const policy = refData.features?.find((f) => f.featureId === feature)?.placementPolicies?.find((p) => p.placementType === placementType);
|
|
222
|
+
const limited = policy?.groupLimits?.flatMap((l) => l.groupIds);
|
|
223
|
+
return limited?.length ? all.filter((g) => limited.includes(g)) : all;
|
|
224
|
+
}
|
|
225
|
+
function maxCountFor(refData, feature, placementType, placementGroup) {
|
|
226
|
+
return refData.features?.find((f) => f.featureId === feature)?.placementPolicies?.find((p) => p.placementType === placementType)?.groupLimits?.find((l) => l.groupIds.includes(placementGroup))?.maxCount;
|
|
227
|
+
}
|
|
228
|
+
function resolveImageGroups(refData, feature, placementType, size) {
|
|
229
|
+
const specs = (refData.imageSpecs ?? []).filter(
|
|
230
|
+
(s) => s.compatiblePlacementTypes.includes(placementType) && fits(s, size.width, size.height)
|
|
231
|
+
);
|
|
232
|
+
const specIds = new Set(specs.map((s) => s.specId));
|
|
233
|
+
const allowed = new Set(groupsForFeature(refData, feature, placementType));
|
|
234
|
+
const mappings = refData.placementTypes?.find((p) => p.placementTypeId === placementType)?.specMappings ?? [];
|
|
235
|
+
const groups = mappings.filter((m) => allowed.has(m.placementGroupId) && m.specs.some((id) => specIds.has(id))).map((m) => m.placementGroupId);
|
|
236
|
+
return { groups: [...new Set(groups)], spec: specs[0] };
|
|
237
|
+
}
|
|
238
|
+
async function runUploadOperations(ops, data) {
|
|
239
|
+
for (const op of ops) {
|
|
240
|
+
const headers = {};
|
|
241
|
+
for (const h of op.requestHeaders) headers[h.name] = h.value;
|
|
242
|
+
const res = await fetch(op.url, {
|
|
243
|
+
method: op.method,
|
|
244
|
+
headers,
|
|
245
|
+
body: data.subarray(op.offset, op.offset + op.length)
|
|
246
|
+
});
|
|
247
|
+
if (!res.ok) {
|
|
248
|
+
throw new Error(`Upload operation failed: ${op.method} ${new URL(op.url).host} \u2192 HTTP ${res.status}`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
async function uploadLibraryAsset(options) {
|
|
253
|
+
const { client, libraryId, filePath, category } = options;
|
|
254
|
+
const data = await readFile(filePath);
|
|
255
|
+
const fileName = basename(filePath);
|
|
256
|
+
const kind = VIDEO_EXTENSIONS.includes(extname(filePath).toLowerCase()) ? "video" : "image";
|
|
257
|
+
const hash = createHash("sha256").update(data).digest("hex").slice(0, 12);
|
|
258
|
+
const referenceName = `${options.referenceName ?? fileName} #${hash}`;
|
|
259
|
+
const media = kind === "image" ? client.appAssetLibraryImages : client.appAssetLibraryVideos;
|
|
260
|
+
const filter = { filter: { referenceName } };
|
|
261
|
+
const existing = kind === "image" ? await client.appAssetLibraries.listImages(libraryId, filter) : await client.appAssetLibraries.listVideos(libraryId, filter);
|
|
262
|
+
const reusable = existing.find(
|
|
263
|
+
(a) => a.attributes.category === category && a.attributes.state && READY_STATES.includes(a.attributes.state)
|
|
264
|
+
);
|
|
265
|
+
if (reusable) {
|
|
266
|
+
return { kind, id: reusable.id, state: reusable.attributes.state, reused: true };
|
|
267
|
+
}
|
|
268
|
+
const reserved = kind === "image" ? await client.appAssetLibraryImages.create({ libraryId, fileName, fileSize: data.length, category, referenceName }) : await client.appAssetLibraryVideos.create({
|
|
269
|
+
libraryId,
|
|
270
|
+
fileName,
|
|
271
|
+
fileSize: data.length,
|
|
272
|
+
category,
|
|
273
|
+
referenceName,
|
|
274
|
+
previewFrameTimeCode: options.previewFrameTimeCode
|
|
275
|
+
});
|
|
276
|
+
await runUploadOperations(reserved.attributes.uploadOperations ?? [], data);
|
|
277
|
+
await media.update(reserved.id, { uploaded: true });
|
|
278
|
+
options.log?.(`uploaded ${fileName} (${kind}, ${data.length} bytes)`);
|
|
279
|
+
const state = await waitForAssetReady(
|
|
280
|
+
() => media.get(reserved.id),
|
|
281
|
+
options.pollIntervalMs ?? 3e3,
|
|
282
|
+
options.timeoutMs ?? (kind === "video" ? 30 * 6e4 : 5 * 6e4)
|
|
283
|
+
);
|
|
284
|
+
return { kind, id: reserved.id, state, reused: false };
|
|
285
|
+
}
|
|
286
|
+
async function waitForAssetReady(get, intervalMs, timeoutMs) {
|
|
287
|
+
const deadline = Date.now() + timeoutMs;
|
|
288
|
+
for (; ; ) {
|
|
289
|
+
const asset = await get();
|
|
290
|
+
const state = asset.attributes.state;
|
|
291
|
+
if (state === "FAILED") {
|
|
292
|
+
const why = (asset.attributes.stateDetails ?? []).map((d) => d.message ?? d.code).filter(Boolean).join("; ");
|
|
293
|
+
throw new Error(`Asset processing failed${why ? `: ${why}` : ""}`);
|
|
294
|
+
}
|
|
295
|
+
if (state && READY_STATES.includes(state)) return state;
|
|
296
|
+
if (Date.now() > deadline) throw new Error(`Asset still ${state ?? "unknown"} after ${timeoutMs / 1e3}s`);
|
|
297
|
+
await new Promise((r) => setTimeout(r, intervalMs));
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
async function listFiles(dir) {
|
|
301
|
+
return (await readdir(dir)).filter((f) => !f.startsWith(".")).sort((a, b) => a.localeCompare(b, void 0, { numeric: true }));
|
|
302
|
+
}
|
|
303
|
+
async function isDir(path) {
|
|
304
|
+
return (await stat(path)).isDirectory();
|
|
305
|
+
}
|
|
306
|
+
async function planLocale(localeDir, refData, feature, folders, warn) {
|
|
307
|
+
const planned = [];
|
|
308
|
+
for (const [folder, placementType] of Object.entries(folders)) {
|
|
309
|
+
const typeDir = join(localeDir, folder);
|
|
310
|
+
if (!existsSync(typeDir)) continue;
|
|
311
|
+
const known = new Set(groupsForFeature(refData, feature, placementType));
|
|
312
|
+
const entries = [];
|
|
313
|
+
for (const entry of await listFiles(typeDir)) {
|
|
314
|
+
const full = join(typeDir, entry);
|
|
315
|
+
if (await isDir(full)) {
|
|
316
|
+
if (!known.has(entry)) {
|
|
317
|
+
warn(`${relative(localeDir, full)}: "${entry}" is not a ${placementType} placement group for ${feature} \u2014 skipped`);
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
for (const f of await listFiles(full)) entries.push({ filePath: join(full, f), group: entry });
|
|
321
|
+
} else {
|
|
322
|
+
entries.push({ filePath: full });
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
for (const { filePath, group } of entries) {
|
|
326
|
+
const ext = extname(filePath).toLowerCase();
|
|
327
|
+
const isVideo = VIDEO_EXTENSIONS.includes(ext);
|
|
328
|
+
if (!isVideo && !IMAGE_EXTENSIONS.includes(ext)) continue;
|
|
329
|
+
const needsVideo = placementType === "APP_PREVIEW";
|
|
330
|
+
const needsImage = placementType === "APP_SCREENSHOT" || placementType === "IMESSAGE_APP_SCREENSHOT";
|
|
331
|
+
if (needsVideo && !isVideo || needsImage && isVideo) {
|
|
332
|
+
warn(`${relative(localeDir, filePath)}: ${isVideo ? "video" : "image"} cannot be a ${placementType} \u2014 skipped`);
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
if (group) {
|
|
336
|
+
planned.push({ filePath, placementType, groups: [group] });
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
if (isVideo) {
|
|
340
|
+
if (known.size === 1) planned.push({ filePath, placementType, groups: [...known] });
|
|
341
|
+
else warn(`${relative(localeDir, filePath)}: put videos in a placement-group folder (one of ${[...known].join(", ")}) \u2014 skipped`);
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
const size = readImageSize(await readFile(filePath));
|
|
345
|
+
if (!size) {
|
|
346
|
+
warn(`${relative(localeDir, filePath)}: could not read image size \u2014 skipped`);
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
const { groups, spec } = resolveImageGroups(refData, feature, placementType, size);
|
|
350
|
+
if (!groups.length) {
|
|
351
|
+
warn(`${relative(localeDir, filePath)}: ${size.width}\xD7${size.height} matches no ${placementType} spec \u2014 skipped`);
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
if (size.alpha && spec && spec.alphaAllowed === false) {
|
|
355
|
+
warn(`${relative(localeDir, filePath)}: has an alpha channel, which Apple rejects for this spec`);
|
|
356
|
+
}
|
|
357
|
+
planned.push({ filePath, placementType, groups: groups.slice(0, 1) });
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return planned;
|
|
361
|
+
}
|
|
362
|
+
async function uploadAssetLibrary(options) {
|
|
363
|
+
const { client } = options;
|
|
364
|
+
const log = options.log ?? (() => {
|
|
365
|
+
});
|
|
366
|
+
const feature = "APP_STORE_VERSIONS";
|
|
367
|
+
const result = { uploaded: 0, reused: 0, placed: 0, removed: 0, warnings: [] };
|
|
368
|
+
const warn = (line) => {
|
|
369
|
+
result.warnings.push(line);
|
|
370
|
+
log(`warning: ${line}`);
|
|
371
|
+
};
|
|
372
|
+
const [library, refData, localizations] = await Promise.all([
|
|
373
|
+
client.appAssetLibraries.getForApp(options.appId),
|
|
374
|
+
client.appAssetLibraries.refData({ features: [feature] }),
|
|
375
|
+
client.appStoreVersions.getLocalizations(options.versionId)
|
|
376
|
+
]);
|
|
377
|
+
const folders = { ...options.folders ?? ASSET_FOLDERS };
|
|
378
|
+
if (options.rootPlacementType) folders["."] = options.rootPlacementType;
|
|
379
|
+
const uploads = /* @__PURE__ */ new Map();
|
|
380
|
+
const uploadOnce = (filePath, placementType) => {
|
|
381
|
+
const key = `${filePath}|${categoryFor(placementType)}`;
|
|
382
|
+
if (!uploads.has(key)) {
|
|
383
|
+
uploads.set(
|
|
384
|
+
key,
|
|
385
|
+
uploadLibraryAsset({
|
|
386
|
+
client,
|
|
387
|
+
libraryId: library.id,
|
|
388
|
+
filePath,
|
|
389
|
+
category: categoryFor(placementType),
|
|
390
|
+
referenceName: relative(options.assetsPath, filePath),
|
|
391
|
+
log
|
|
392
|
+
}).then((a) => {
|
|
393
|
+
if (a.reused) result.reused++;
|
|
394
|
+
else result.uploaded++;
|
|
395
|
+
return a;
|
|
396
|
+
})
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
return uploads.get(key);
|
|
400
|
+
};
|
|
401
|
+
for (const loc of localizations) {
|
|
402
|
+
const localeDir = join(options.assetsPath, loc.attributes.locale);
|
|
403
|
+
if (!existsSync(localeDir)) continue;
|
|
404
|
+
const target = { kind: "appStoreVersionLocalization", id: loc.id };
|
|
405
|
+
const plan = await planLocale(localeDir, refData, feature, folders, warn);
|
|
406
|
+
const slots = /* @__PURE__ */ new Map();
|
|
407
|
+
for (const p of plan) {
|
|
408
|
+
for (const group of p.groups) {
|
|
409
|
+
const key = `${p.placementType}|${group}`;
|
|
410
|
+
if (!slots.has(key)) slots.set(key, { placementType: p.placementType, group, files: [] });
|
|
411
|
+
slots.get(key).files.push(p.filePath);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
for (const slot of slots.values()) {
|
|
415
|
+
const where = `${loc.attributes.locale} ${slot.placementType} ${slot.group}`;
|
|
416
|
+
const max = maxCountFor(refData, feature, slot.placementType, slot.group);
|
|
417
|
+
if (max !== void 0 && slot.files.length > max) {
|
|
418
|
+
warn(`${where}: ${slot.files.length} files but Apple allows ${max} \u2014 keeping the first ${max}`);
|
|
419
|
+
slot.files = slot.files.slice(0, max);
|
|
420
|
+
}
|
|
421
|
+
const existing = await client.appAssetLibraryPlacements.listForTarget(target, {
|
|
422
|
+
placementType: slot.placementType,
|
|
423
|
+
placementGroup: slot.group,
|
|
424
|
+
include: "image,video"
|
|
425
|
+
});
|
|
426
|
+
if (options.overwrite) {
|
|
427
|
+
for (const p of existing) {
|
|
428
|
+
await client.appAssetLibraryPlacements.delete(p.id);
|
|
429
|
+
result.removed++;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
const kept = options.overwrite ? [] : existing;
|
|
433
|
+
const keptAssetIds = new Set(kept.map((p) => placementAssetId(p)).filter(Boolean));
|
|
434
|
+
const ours = [];
|
|
435
|
+
for (const filePath of slot.files) {
|
|
436
|
+
const asset = await uploadOnce(filePath, slot.placementType);
|
|
437
|
+
if (keptAssetIds.has(asset.id)) continue;
|
|
438
|
+
const placement = await client.appAssetLibraryPlacements.create({
|
|
439
|
+
placementType: slot.placementType,
|
|
440
|
+
placementGroup: slot.group,
|
|
441
|
+
...asset.kind === "image" ? { imageId: asset.id } : { videoId: asset.id },
|
|
442
|
+
target
|
|
443
|
+
});
|
|
444
|
+
ours.push(placement.id);
|
|
445
|
+
result.placed++;
|
|
446
|
+
}
|
|
447
|
+
log(`${where}: placed ${ours.length}${kept.length ? `, kept ${kept.length}` : ""}`);
|
|
448
|
+
const orderable = slot.placementType === "APP_SCREENSHOT" || slot.placementType === "APP_PREVIEW" || slot.placementType === "IMESSAGE_APP_SCREENSHOT";
|
|
449
|
+
if (orderable && ours.length + kept.length > 1) {
|
|
450
|
+
await client.appAssetLibraryPlacements.order({
|
|
451
|
+
placementGroup: slot.group,
|
|
452
|
+
placementIds: [...ours, ...kept.map((p) => p.id)],
|
|
453
|
+
target
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return result;
|
|
459
|
+
}
|
|
460
|
+
function placementAssetId(p) {
|
|
461
|
+
for (const rel of ["image", "video"]) {
|
|
462
|
+
const data = p.relationships?.[rel]?.data;
|
|
463
|
+
if (data?.id) return data.id;
|
|
464
|
+
}
|
|
465
|
+
return void 0;
|
|
466
|
+
}
|
|
167
467
|
|
|
168
468
|
// src/deliver/index.ts
|
|
169
469
|
async function uploadToAppStore(options) {
|
|
@@ -200,11 +500,36 @@ async function uploadToAppStore(options) {
|
|
|
200
500
|
copyright: options.copyright
|
|
201
501
|
});
|
|
202
502
|
}
|
|
503
|
+
const log = (line) => options.onOutput?.(`${line}
|
|
504
|
+
`);
|
|
203
505
|
if (!options.skipScreenshots && options.screenshotsPath && existsSync(options.screenshotsPath)) {
|
|
204
|
-
|
|
506
|
+
if (options.useAssetLibrary) {
|
|
507
|
+
await uploadAssetLibrary({
|
|
508
|
+
client: options.client,
|
|
509
|
+
appId: app.id,
|
|
510
|
+
versionId: version.id,
|
|
511
|
+
assetsPath: options.screenshotsPath,
|
|
512
|
+
folders: {},
|
|
513
|
+
rootPlacementType: "APP_SCREENSHOT",
|
|
514
|
+
overwrite: options.overwriteAssets,
|
|
515
|
+
log
|
|
516
|
+
});
|
|
517
|
+
} else {
|
|
518
|
+
await uploadScreenshots({
|
|
519
|
+
client: options.client,
|
|
520
|
+
versionId: version.id,
|
|
521
|
+
screenshotsPath: options.screenshotsPath
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
if (!options.skipAssets && options.assetsPath && existsSync(options.assetsPath)) {
|
|
526
|
+
await uploadAssetLibrary({
|
|
205
527
|
client: options.client,
|
|
528
|
+
appId: app.id,
|
|
206
529
|
versionId: version.id,
|
|
207
|
-
|
|
530
|
+
assetsPath: options.assetsPath,
|
|
531
|
+
overwrite: options.overwriteAssets,
|
|
532
|
+
log
|
|
208
533
|
});
|
|
209
534
|
}
|
|
210
535
|
if (!options.skipBinaryUpload) {
|
|
@@ -289,17 +614,7 @@ async function uploadScreenshots(options) {
|
|
|
289
614
|
fileName: file,
|
|
290
615
|
fileSize: fileData.length
|
|
291
616
|
});
|
|
292
|
-
|
|
293
|
-
if (ops) {
|
|
294
|
-
for (const op of ops) {
|
|
295
|
-
const chunk = fileData.subarray(op.offset, op.offset + op.length);
|
|
296
|
-
const headers = {};
|
|
297
|
-
for (const h of op.requestHeaders) {
|
|
298
|
-
headers[h.name] = h.value;
|
|
299
|
-
}
|
|
300
|
-
await fetch(op.url, { method: op.method, headers, body: chunk });
|
|
301
|
-
}
|
|
302
|
-
}
|
|
617
|
+
await runUploadOperations(reserved.attributes.uploadOperations ?? [], fileData);
|
|
303
618
|
await options.client.appScreenshots.commitScreenshot(reserved.id, {
|
|
304
619
|
sourceFileChecksum: checksum,
|
|
305
620
|
uploaded: true
|
|
@@ -317,6 +632,6 @@ function detectDisplayType(filename) {
|
|
|
317
632
|
return null;
|
|
318
633
|
}
|
|
319
634
|
|
|
320
|
-
export { loadMetadata, submitForReview, uploadMetadata, uploadScreenshots, uploadToAppStore };
|
|
635
|
+
export { ASSET_FOLDERS, categoryFor, loadMetadata, readImageSize, resolveImageGroups, submitForReview, uploadAssetLibrary, uploadLibraryAsset, uploadMetadata, uploadScreenshots, uploadToAppStore };
|
|
321
636
|
//# sourceMappingURL=index.mjs.map
|
|
322
637
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/xcode/platform.ts","../../src/xcode/upload.ts","../../src/deliver/metadata.ts","../../src/deliver/index.ts"],"names":["join","uploadWithAltool","readdir","readFile"],"mappings":"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","file":"index.mjs","sourcesContent":["export function requireMacOS(feature: string): void {\n if (process.platform !== \"darwin\") {\n throw new Error(\n `${feature} requires macOS. This operation uses Xcode command-line tools ` +\n `which are not available on ${process.platform}.`\n );\n }\n}\n\nexport function isMacOS(): boolean {\n return process.platform === \"darwin\";\n}\n","import { spawn } from \"node:child_process\";\nimport { writeFile, unlink, mkdtemp } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport { requireMacOS } from \"./platform.js\";\n\nexport async function uploadWithAltool(options: {\n filePath: string;\n apiKeyId: string;\n apiIssuerId: string;\n apiPrivateKey?: string;\n apiKeyPath?: string;\n platform?: string;\n onOutput?: (chunk: string) => void;\n}): Promise<{ success: boolean; output: string }> {\n requireMacOS(\"altool upload\");\n\n // Write temp .p8 if private key content provided\n let keyDir: string | undefined;\n if (options.apiPrivateKey && !options.apiKeyPath) {\n keyDir = await mkdtemp(join(tmpdir(), \"fastnode-altool-\"));\n const keyPath = join(keyDir, `AuthKey_${options.apiKeyId}.p8`);\n await writeFile(keyPath, options.apiPrivateKey);\n }\n\n const args = [\n \"altool\",\n \"--upload-app\",\n \"-f\", options.filePath,\n \"-t\", options.platform ?? \"ios\",\n \"--apiKey\", options.apiKeyId,\n \"--apiIssuer\", options.apiIssuerId,\n ];\n\n const env = { ...process.env };\n if (keyDir) {\n env.API_PRIVATE_KEYS_DIR = keyDir;\n }\n\n return new Promise<{ success: boolean; output: string }>((resolve) => {\n const child = spawn(\"xcrun\", args, {\n env,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n let output = \"\";\n\n child.stdout.on(\"data\", (data: Buffer) => {\n const chunk = data.toString();\n output += chunk;\n options.onOutput?.(chunk);\n });\n\n child.stderr.on(\"data\", (data: Buffer) => {\n const chunk = data.toString();\n output += chunk;\n options.onOutput?.(chunk);\n });\n\n child.on(\"close\", async (code) => {\n if (keyDir) {\n const keyPath = join(keyDir, `AuthKey_${options.apiKeyId}.p8`);\n await unlink(keyPath).catch(() => {});\n }\n resolve({ success: code === 0, output });\n });\n });\n}\n","import { readFile, readdir, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport interface LocalizedMetadata {\n locale: string;\n description?: string;\n keywords?: string;\n releaseNotes?: string;\n supportUrl?: string;\n marketingUrl?: string;\n promotionalText?: string;\n name?: string;\n subtitle?: string;\n privacyUrl?: string;\n}\n\n/**\n * Review information submitted to App Store Connect for App Review.\n * Mirrors Fastlane deliver's `review_first_name`, `review_last_name`,\n * etc. (upload_metadata.rb lines 45-51), mapping to ASC's\n * `appStoreReviewDetails` attribute names.\n */\nexport interface ReviewInformation {\n firstName?: string;\n lastName?: string;\n phoneNumber?: string;\n emailAddress?: string;\n demoUser?: string;\n demoPassword?: string;\n notes?: string;\n}\n\nexport interface MetadataSet {\n localizations: LocalizedMetadata[];\n copyright?: string;\n /** Typed review information extracted from `review_information/`. */\n reviewInformation?: ReviewInformation;\n /** Raw review information map, including any unrecognised filenames. */\n reviewInfo?: Record<string, string>;\n}\n\n/**\n * Map from a `metadata/review_information/` filename (without `.txt`) to\n * its `ReviewInformation` field. Supports both the modern ASC-aligned\n * names and Fastlane's legacy `review_*` names.\n */\nconst REVIEW_FILENAME_TO_FIELD: Record<string, keyof ReviewInformation> = {\n // Modern (ASC-aligned) filenames\n first_name: \"firstName\",\n last_name: \"lastName\",\n phone_number: \"phoneNumber\",\n email_address: \"emailAddress\",\n demo_user: \"demoUser\",\n demo_password: \"demoPassword\",\n notes: \"notes\",\n // Legacy Fastlane filenames\n review_first_name: \"firstName\",\n review_last_name: \"lastName\",\n review_phone_number: \"phoneNumber\",\n review_email: \"emailAddress\",\n review_demo_user: \"demoUser\",\n review_demo_password: \"demoPassword\",\n review_notes: \"notes\",\n};\n\nconst LOCALE_FILES: Record<string, string> = {\n \"description.txt\": \"description\",\n \"keywords.txt\": \"keywords\",\n \"release_notes.txt\": \"releaseNotes\",\n \"support_url.txt\": \"supportUrl\",\n \"marketing_url.txt\": \"marketingUrl\",\n \"promotional_text.txt\": \"promotionalText\",\n \"name.txt\": \"name\",\n \"subtitle.txt\": \"subtitle\",\n \"privacy_url.txt\": \"privacyUrl\",\n};\n\nexport async function loadMetadata(metadataPath: string): Promise<MetadataSet> {\n const localizations: LocalizedMetadata[] = [];\n let copyright: string | undefined;\n let reviewInfo: Record<string, string> | undefined;\n let reviewInformation: ReviewInformation | undefined;\n\n // Read copyright\n try {\n copyright = (await readFile(join(metadataPath, \"copyright.txt\"), \"utf-8\")).trim();\n } catch {\n // Optional\n }\n\n // Read review info\n const reviewDir = join(metadataPath, \"review_information\");\n try {\n const reviewStat = await stat(reviewDir);\n if (reviewStat.isDirectory()) {\n reviewInfo = {};\n reviewInformation = {};\n const files = await readdir(reviewDir);\n for (const file of files) {\n if (!file.endsWith(\".txt\")) continue;\n const key = file.replace(\".txt\", \"\");\n const content = (await readFile(join(reviewDir, file), \"utf-8\")).trim();\n reviewInfo[key] = content;\n const field = REVIEW_FILENAME_TO_FIELD[key];\n if (field && content) reviewInformation[field] = content;\n }\n }\n } catch {\n // Optional\n }\n\n // Read locale directories\n const entries = await readdir(metadataPath, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n if (entry.name === \"review_information\" || entry.name === \"trade_representative_contact_information\") continue;\n\n const locale = entry.name;\n const localeDir = join(metadataPath, locale);\n const localization: LocalizedMetadata = { locale };\n\n for (const [filename, key] of Object.entries(LOCALE_FILES)) {\n try {\n const content = (await readFile(join(localeDir, filename), \"utf-8\")).trim();\n if (content) {\n (localization as any)[key] = content;\n }\n } catch {\n // File doesn't exist — optional\n }\n }\n\n localizations.push(localization);\n }\n\n return { localizations, copyright, reviewInfo, reviewInformation };\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile, readdir, stat } from \"node:fs/promises\";\nimport { join, extname } from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport type { AppStoreConnectClient } from \"../client/index.js\";\nimport type { Platform, ReleaseType } from \"../types/index.js\";\nimport { loadMetadata } from \"./metadata.js\";\n\nexport { loadMetadata } from \"./metadata.js\";\nexport type { LocalizedMetadata, MetadataSet } from \"./metadata.js\";\n\nexport interface DeliverOptions {\n client: AppStoreConnectClient;\n bundleIdentifier: string;\n appVersion?: string;\n platform?: Platform;\n ipaPath?: string;\n pkgPath?: string;\n metadataPath?: string;\n screenshotsPath?: string;\n submitForReview?: boolean;\n automaticRelease?: boolean;\n releaseType?: ReleaseType;\n skipBinaryUpload?: boolean;\n skipMetadata?: boolean;\n skipScreenshots?: boolean;\n force?: boolean;\n apiKeyId?: string;\n apiIssuerId?: string;\n apiPrivateKey?: string;\n copyright?: string;\n onOutput?: (chunk: string) => void;\n}\n\nexport interface DeliverResult {\n appId: string;\n versionId: string;\n submitted: boolean;\n}\n\nexport async function uploadToAppStore(options: DeliverOptions): Promise<DeliverResult> {\n const platform = options.platform ?? \"IOS\";\n\n // Find app\n const app = await options.client.apps.findByBundleId(options.bundleIdentifier);\n if (!app) throw new Error(`App not found: ${options.bundleIdentifier}`);\n\n // Find or create version\n const versions = await options.client.appStoreVersions.listForApp(app.id, {\n filter: { platform },\n });\n\n let version = versions.find(\n (v) =>\n v.attributes.appStoreState === \"PREPARE_FOR_SUBMISSION\" ||\n v.attributes.appStoreState === \"DEVELOPER_REJECTED\"\n );\n\n if (!version && options.appVersion) {\n version = await options.client.appStoreVersions.create({\n appId: app.id,\n versionString: options.appVersion,\n platform,\n releaseType: options.releaseType,\n });\n }\n\n if (!version) {\n throw new Error(\"No editable app store version found. Pass appVersion to create one.\");\n }\n\n // Upload metadata\n if (!options.skipMetadata && options.metadataPath && existsSync(options.metadataPath)) {\n await uploadMetadata({\n client: options.client,\n appId: app.id,\n versionId: version.id,\n metadataPath: options.metadataPath,\n });\n }\n\n // Set copyright\n if (options.copyright) {\n await options.client.appStoreVersions.update(version.id, {\n copyright: options.copyright,\n });\n }\n\n // Upload screenshots\n if (!options.skipScreenshots && options.screenshotsPath && existsSync(options.screenshotsPath)) {\n await uploadScreenshots({\n client: options.client,\n versionId: version.id,\n screenshotsPath: options.screenshotsPath,\n });\n }\n\n // Upload binary\n if (!options.skipBinaryUpload) {\n const binaryPath = options.ipaPath ?? options.pkgPath;\n if (binaryPath && options.apiKeyId && options.apiIssuerId) {\n const { uploadWithAltool } = await import(\"../xcode/upload.js\");\n await uploadWithAltool({\n filePath: binaryPath,\n apiKeyId: options.apiKeyId,\n apiIssuerId: options.apiIssuerId,\n apiPrivateKey: options.apiPrivateKey,\n onOutput: options.onOutput,\n });\n }\n }\n\n // Submit for review\n let submitted = false;\n if (options.submitForReview) {\n await submitForReview({\n client: options.client,\n appId: app.id,\n versionId: version.id,\n });\n submitted = true;\n }\n\n return { appId: app.id, versionId: version.id, submitted };\n}\n\nexport async function submitForReview(options: {\n client: AppStoreConnectClient;\n appId: string;\n versionId: string;\n}): Promise<void> {\n await options.client.reviewSubmissions.submitVersion(options.versionId);\n}\n\nexport async function uploadMetadata(options: {\n client: AppStoreConnectClient;\n appId: string;\n versionId: string;\n metadataPath: string;\n}): Promise<void> {\n const metadata = await loadMetadata(options.metadataPath);\n\n // Get existing localizations\n const existingLocs = await options.client.appStoreVersions.getLocalizations(options.versionId);\n\n for (const loc of metadata.localizations) {\n const existing = existingLocs.find((e) => e.attributes.locale === loc.locale);\n const attrs: Record<string, string | undefined> = {};\n if (loc.description) attrs.description = loc.description;\n if (loc.keywords) attrs.keywords = loc.keywords;\n if (loc.releaseNotes) attrs.whatsNew = loc.releaseNotes;\n if (loc.supportUrl) attrs.supportUrl = loc.supportUrl;\n if (loc.marketingUrl) attrs.marketingUrl = loc.marketingUrl;\n if (loc.promotionalText) attrs.promotionalText = loc.promotionalText;\n\n if (existing) {\n await options.client.appStoreVersions.updateLocalization(existing.id, attrs);\n } else {\n await options.client.appStoreVersions.createLocalization({\n versionId: options.versionId,\n locale: loc.locale,\n ...attrs,\n });\n }\n }\n\n // Update copyright\n if (metadata.copyright) {\n await options.client.appStoreVersions.update(options.versionId, {\n copyright: metadata.copyright,\n });\n }\n}\n\nexport async function uploadScreenshots(options: {\n client: AppStoreConnectClient;\n versionId: string;\n screenshotsPath: string;\n}): Promise<void> {\n const localizations = await options.client.appStoreVersions.getLocalizations(options.versionId);\n\n for (const loc of localizations) {\n const localeDir = join(options.screenshotsPath, loc.attributes.locale);\n if (!existsSync(localeDir)) continue;\n\n const sets = await options.client.appScreenshots.listSetsForLocalization(loc.id);\n const files = (await readdir(localeDir)).filter((f) =>\n [\".png\", \".jpg\", \".jpeg\"].includes(extname(f).toLowerCase())\n );\n\n for (const file of files) {\n const filePath = join(localeDir, file);\n const fileData = await readFile(filePath);\n const checksum = createHash(\"md5\").update(fileData).digest(\"hex\");\n\n // Determine display type from filename convention\n const displayType = detectDisplayType(file);\n if (!displayType) continue;\n\n // Find or create screenshot set\n let set = sets.find((s) => s.attributes.screenshotDisplayType === displayType);\n if (!set) {\n set = await options.client.appScreenshots.createSet({\n localizationId: loc.id,\n screenshotDisplayType: displayType,\n });\n }\n\n // Reserve, upload, commit\n const reserved = await options.client.appScreenshots.reserveScreenshot({\n setId: set.id,\n fileName: file,\n fileSize: fileData.length,\n });\n\n // Upload chunks\n const ops = reserved.attributes.uploadOperations;\n if (ops) {\n for (const op of ops) {\n const chunk = fileData.subarray(op.offset, op.offset + op.length);\n const headers: Record<string, string> = {};\n for (const h of op.requestHeaders) {\n headers[h.name] = h.value;\n }\n await fetch(op.url, { method: op.method, headers, body: chunk });\n }\n }\n\n await options.client.appScreenshots.commitScreenshot(reserved.id, {\n sourceFileChecksum: checksum,\n uploaded: true,\n });\n }\n }\n}\n\nfunction detectDisplayType(filename: string): string | null {\n const lower = filename.toLowerCase();\n if (lower.includes(\"6.7\") || lower.includes(\"iphone_67\")) return \"APP_IPHONE_67\";\n if (lower.includes(\"6.5\") || lower.includes(\"iphone_65\")) return \"APP_IPHONE_65\";\n if (lower.includes(\"5.5\") || lower.includes(\"iphone_55\")) return \"APP_IPHONE_55\";\n if (lower.includes(\"ipad_pro_3gen\") || lower.includes(\"12.9\")) return \"APP_IPAD_PRO_3GEN_129\";\n if (lower.includes(\"ipad_pro\") || lower.includes(\"ipad\")) return \"APP_IPAD_PRO_129\";\n return null;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/xcode/platform.ts","../../src/xcode/upload.ts","../../src/deliver/metadata.ts","../../src/deliver/assets.ts","../../src/deliver/index.ts"],"names":["join","readFile","readdir","stat","existsSync","uploadWithAltool","extname","createHash"],"mappings":"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","file":"index.mjs","sourcesContent":["export function requireMacOS(feature: string): void {\n if (process.platform !== \"darwin\") {\n throw new Error(\n `${feature} requires macOS. This operation uses Xcode command-line tools ` +\n `which are not available on ${process.platform}.`\n );\n }\n}\n\nexport function isMacOS(): boolean {\n return process.platform === \"darwin\";\n}\n","import { spawn } from \"node:child_process\";\nimport { writeFile, unlink, mkdtemp } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport { requireMacOS } from \"./platform.js\";\n\nexport async function uploadWithAltool(options: {\n filePath: string;\n apiKeyId: string;\n apiIssuerId: string;\n apiPrivateKey?: string;\n apiKeyPath?: string;\n platform?: string;\n onOutput?: (chunk: string) => void;\n}): Promise<{ success: boolean; output: string }> {\n requireMacOS(\"altool upload\");\n\n // Write temp .p8 if private key content provided\n let keyDir: string | undefined;\n if (options.apiPrivateKey && !options.apiKeyPath) {\n keyDir = await mkdtemp(join(tmpdir(), \"fastnode-altool-\"));\n const keyPath = join(keyDir, `AuthKey_${options.apiKeyId}.p8`);\n await writeFile(keyPath, options.apiPrivateKey);\n }\n\n const args = [\n \"altool\",\n \"--upload-app\",\n \"-f\", options.filePath,\n \"-t\", options.platform ?? \"ios\",\n \"--apiKey\", options.apiKeyId,\n \"--apiIssuer\", options.apiIssuerId,\n ];\n\n const env = { ...process.env };\n if (keyDir) {\n env.API_PRIVATE_KEYS_DIR = keyDir;\n }\n\n return new Promise<{ success: boolean; output: string }>((resolve) => {\n const child = spawn(\"xcrun\", args, {\n env,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n let output = \"\";\n\n child.stdout.on(\"data\", (data: Buffer) => {\n const chunk = data.toString();\n output += chunk;\n options.onOutput?.(chunk);\n });\n\n child.stderr.on(\"data\", (data: Buffer) => {\n const chunk = data.toString();\n output += chunk;\n options.onOutput?.(chunk);\n });\n\n child.on(\"close\", async (code) => {\n if (keyDir) {\n const keyPath = join(keyDir, `AuthKey_${options.apiKeyId}.p8`);\n await unlink(keyPath).catch(() => {});\n }\n resolve({ success: code === 0, output });\n });\n });\n}\n","import { readFile, readdir, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport interface LocalizedMetadata {\n locale: string;\n description?: string;\n keywords?: string;\n releaseNotes?: string;\n supportUrl?: string;\n marketingUrl?: string;\n promotionalText?: string;\n name?: string;\n subtitle?: string;\n privacyUrl?: string;\n}\n\n/**\n * Review information submitted to App Store Connect for App Review.\n * Mirrors Fastlane deliver's `review_first_name`, `review_last_name`,\n * etc. (upload_metadata.rb lines 45-51), mapping to ASC's\n * `appStoreReviewDetails` attribute names.\n */\nexport interface ReviewInformation {\n firstName?: string;\n lastName?: string;\n phoneNumber?: string;\n emailAddress?: string;\n demoUser?: string;\n demoPassword?: string;\n notes?: string;\n}\n\nexport interface MetadataSet {\n localizations: LocalizedMetadata[];\n copyright?: string;\n /** Typed review information extracted from `review_information/`. */\n reviewInformation?: ReviewInformation;\n /** Raw review information map, including any unrecognised filenames. */\n reviewInfo?: Record<string, string>;\n}\n\n/**\n * Map from a `metadata/review_information/` filename (without `.txt`) to\n * its `ReviewInformation` field. Supports both the modern ASC-aligned\n * names and Fastlane's legacy `review_*` names.\n */\nconst REVIEW_FILENAME_TO_FIELD: Record<string, keyof ReviewInformation> = {\n // Modern (ASC-aligned) filenames\n first_name: \"firstName\",\n last_name: \"lastName\",\n phone_number: \"phoneNumber\",\n email_address: \"emailAddress\",\n demo_user: \"demoUser\",\n demo_password: \"demoPassword\",\n notes: \"notes\",\n // Legacy Fastlane filenames\n review_first_name: \"firstName\",\n review_last_name: \"lastName\",\n review_phone_number: \"phoneNumber\",\n review_email: \"emailAddress\",\n review_demo_user: \"demoUser\",\n review_demo_password: \"demoPassword\",\n review_notes: \"notes\",\n};\n\nconst LOCALE_FILES: Record<string, string> = {\n \"description.txt\": \"description\",\n \"keywords.txt\": \"keywords\",\n \"release_notes.txt\": \"releaseNotes\",\n \"support_url.txt\": \"supportUrl\",\n \"marketing_url.txt\": \"marketingUrl\",\n \"promotional_text.txt\": \"promotionalText\",\n \"name.txt\": \"name\",\n \"subtitle.txt\": \"subtitle\",\n \"privacy_url.txt\": \"privacyUrl\",\n};\n\nexport async function loadMetadata(metadataPath: string): Promise<MetadataSet> {\n const localizations: LocalizedMetadata[] = [];\n let copyright: string | undefined;\n let reviewInfo: Record<string, string> | undefined;\n let reviewInformation: ReviewInformation | undefined;\n\n // Read copyright\n try {\n copyright = (await readFile(join(metadataPath, \"copyright.txt\"), \"utf-8\")).trim();\n } catch {\n // Optional\n }\n\n // Read review info\n const reviewDir = join(metadataPath, \"review_information\");\n try {\n const reviewStat = await stat(reviewDir);\n if (reviewStat.isDirectory()) {\n reviewInfo = {};\n reviewInformation = {};\n const files = await readdir(reviewDir);\n for (const file of files) {\n if (!file.endsWith(\".txt\")) continue;\n const key = file.replace(\".txt\", \"\");\n const content = (await readFile(join(reviewDir, file), \"utf-8\")).trim();\n reviewInfo[key] = content;\n const field = REVIEW_FILENAME_TO_FIELD[key];\n if (field && content) reviewInformation[field] = content;\n }\n }\n } catch {\n // Optional\n }\n\n // Read locale directories\n const entries = await readdir(metadataPath, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n if (entry.name === \"review_information\" || entry.name === \"trade_representative_contact_information\") continue;\n\n const locale = entry.name;\n const localeDir = join(metadataPath, locale);\n const localization: LocalizedMetadata = { locale };\n\n for (const [filename, key] of Object.entries(LOCALE_FILES)) {\n try {\n const content = (await readFile(join(localeDir, filename), \"utf-8\")).trim();\n if (content) {\n (localization as any)[key] = content;\n }\n } catch {\n // File doesn't exist — optional\n }\n }\n\n localizations.push(localization);\n }\n\n return { localizations, copyright, reviewInfo, reviewInformation };\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile, readdir, stat } from \"node:fs/promises\";\nimport { basename, extname, join, relative } from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport type { AppStoreConnectClient } from \"../client/index.js\";\nimport type {\n AppAssetLibraryRefDatumAttributes,\n AppAssetLibraryImageSpec,\n} from \"../resources/app-asset-libraries.js\";\nimport type { PlacementTarget } from \"../resources/app-asset-library-placements.js\";\nimport type { UploadOperation } from \"../resources/app-screenshots.js\";\nimport type {\n AppAssetLibraryAssetCategory,\n AppAssetLibraryAssetState,\n AppAssetLibraryFeature,\n AppAssetLibraryPlacementType,\n} from \"../types/enums.js\";\n\n/**\n * Folder name under `<assetsPath>/<locale>/` → what gets placed there.\n *\n * assets/en-US/screenshots/01-home.png APP_SCREENSHOT (group from image size)\n * assets/en-US/screenshots/IPHONE_DUO/01.png APP_SCREENSHOT in an explicit group\n * assets/en-US/previews/IPHONE_…_PROFILE/a.mp4 APP_PREVIEW (videos need the group folder\n * unless the type has a single group)\n * assets/en-US/header/hero.png PRODUCT_PAGE_HEADER_ASSET\n * assets/en-US/search_results/card.png APP_STORE_SEARCH_RESULTS_ASSET\n */\nexport const ASSET_FOLDERS: Record<string, AppAssetLibraryPlacementType> = {\n screenshots: \"APP_SCREENSHOT\",\n imessage_screenshots: \"IMESSAGE_APP_SCREENSHOT\",\n previews: \"APP_PREVIEW\",\n header: \"PRODUCT_PAGE_HEADER_ASSET\",\n search_results: \"APP_STORE_SEARCH_RESULTS_ASSET\",\n event_card: \"EVENT_CARD_ASSET\",\n event_details: \"EVENT_DETAILS_PAGE_ASSET\",\n};\n\nconst IMAGE_EXTENSIONS = [\".png\", \".jpg\", \".jpeg\"];\nconst VIDEO_EXTENSIONS = [\".mp4\", \".mov\", \".m4v\"];\nconst READY_STATES: AppAssetLibraryAssetState[] = [\n \"COMPLETE\",\n \"PREPARE_FOR_SUBMISSION\",\n \"READY_FOR_REVIEW\",\n \"WAITING_FOR_REVIEW\",\n \"IN_REVIEW\",\n \"ACCEPTED\",\n \"APPROVED\",\n];\n\nexport function categoryFor(placementType: AppAssetLibraryPlacementType): AppAssetLibraryAssetCategory {\n return placementType === \"APP_SCREENSHOT\" ||\n placementType === \"IMESSAGE_APP_SCREENSHOT\" ||\n placementType === \"APP_PREVIEW\"\n ? \"APP_SCREENSHOTS_AND_PREVIEWS\"\n : \"CREATIVE_ASSETS\";\n}\n\n// ── Image dimensions (PNG / JPEG headers, no dependency) ───────────────────\n\nexport function readImageSize(data: Buffer): { width: number; height: number; alpha?: boolean } | null {\n // PNG: signature, then IHDR width/height at 16/20, colour type at 25\n if (data.length >= 26 && data.readUInt32BE(0) === 0x89504e47) {\n const colorType = data[25];\n return {\n width: data.readUInt32BE(16),\n height: data.readUInt32BE(20),\n alpha: colorType === 4 || colorType === 6,\n };\n }\n // JPEG: walk markers to the first SOFn\n if (data.length >= 4 && data[0] === 0xff && data[1] === 0xd8) {\n let offset = 2;\n while (offset + 9 < data.length) {\n if (data[offset] !== 0xff) return null;\n const marker = data[offset + 1];\n const length = data.readUInt16BE(offset + 2);\n const isSof = marker >= 0xc0 && marker <= 0xcf && marker !== 0xc4 && marker !== 0xc8 && marker !== 0xcc;\n if (isSof) {\n return { height: data.readUInt16BE(offset + 5), width: data.readUInt16BE(offset + 7), alpha: false };\n }\n offset += 2 + length;\n }\n }\n return null;\n}\n\n// ── Spec / placement-group resolution ──────────────────────────────────────\n\nfunction fits(spec: AppAssetLibraryImageSpec, width: number, height: number): boolean {\n const d = spec.dimensions;\n return width >= d.minWidth && width <= d.maxWidth && height >= d.minHeight && height <= d.maxHeight;\n}\n\n/** Placement groups the feature allows for a placement type (all, if the feature lists none). */\nfunction groupsForFeature(\n refData: AppAssetLibraryRefDatumAttributes,\n feature: AppAssetLibraryFeature,\n placementType: AppAssetLibraryPlacementType\n): string[] {\n const mappings = refData.placementTypes?.find((p) => p.placementTypeId === placementType)?.specMappings ?? [];\n const all = mappings.map((m) => m.placementGroupId);\n const policy = refData.features\n ?.find((f) => f.featureId === feature)\n ?.placementPolicies?.find((p) => p.placementType === placementType);\n const limited = policy?.groupLimits?.flatMap((l) => l.groupIds);\n return limited?.length ? all.filter((g) => limited.includes(g)) : all;\n}\n\nexport function maxCountFor(\n refData: AppAssetLibraryRefDatumAttributes,\n feature: AppAssetLibraryFeature,\n placementType: AppAssetLibraryPlacementType,\n placementGroup: string\n): number | undefined {\n return refData.features\n ?.find((f) => f.featureId === feature)\n ?.placementPolicies?.find((p) => p.placementType === placementType)\n ?.groupLimits?.find((l) => l.groupIds.includes(placementGroup))?.maxCount;\n}\n\n/**\n * Which placement groups an image of this size can go into, read from\n * Apple's reference data (never hard-coded — new devices appear there first).\n */\nexport function resolveImageGroups(\n refData: AppAssetLibraryRefDatumAttributes,\n feature: AppAssetLibraryFeature,\n placementType: AppAssetLibraryPlacementType,\n size: { width: number; height: number }\n): { groups: string[]; spec?: AppAssetLibraryImageSpec } {\n const specs = (refData.imageSpecs ?? []).filter(\n (s) => s.compatiblePlacementTypes.includes(placementType) && fits(s, size.width, size.height)\n );\n const specIds = new Set(specs.map((s) => s.specId));\n const allowed = new Set(groupsForFeature(refData, feature, placementType));\n const mappings = refData.placementTypes?.find((p) => p.placementTypeId === placementType)?.specMappings ?? [];\n const groups = mappings\n .filter((m) => allowed.has(m.placementGroupId) && m.specs.some((id) => specIds.has(id)))\n .map((m) => m.placementGroupId);\n return { groups: [...new Set(groups)], spec: specs[0] };\n}\n\n// ── Upload ─────────────────────────────────────────────────────────────────\n\nexport async function runUploadOperations(ops: UploadOperation[], data: Buffer): Promise<void> {\n for (const op of ops) {\n const headers: Record<string, string> = {};\n for (const h of op.requestHeaders) headers[h.name] = h.value;\n const res = await fetch(op.url, {\n method: op.method,\n headers,\n body: data.subarray(op.offset, op.offset + op.length),\n });\n if (!res.ok) {\n throw new Error(`Upload operation failed: ${op.method} ${new URL(op.url).host} → HTTP ${res.status}`);\n }\n }\n}\n\nexport interface UploadedAsset {\n kind: \"image\" | \"video\";\n id: string;\n state: AppAssetLibraryAssetState;\n reused: boolean;\n}\n\n/**\n * Upload one file into the app's asset library and wait until it can be\n * placed. A file already in the library (same content hash in its reference\n * name) is reused instead of uploaded again.\n */\nexport async function uploadLibraryAsset(options: {\n client: AppStoreConnectClient;\n libraryId: string;\n filePath: string;\n category: AppAssetLibraryAssetCategory;\n referenceName?: string;\n previewFrameTimeCode?: string;\n pollIntervalMs?: number;\n timeoutMs?: number;\n log?: (line: string) => void;\n}): Promise<UploadedAsset> {\n const { client, libraryId, filePath, category } = options;\n const data = await readFile(filePath);\n const fileName = basename(filePath);\n const kind = VIDEO_EXTENSIONS.includes(extname(filePath).toLowerCase()) ? \"video\" : \"image\";\n const hash = createHash(\"sha256\").update(data).digest(\"hex\").slice(0, 12);\n const referenceName = `${options.referenceName ?? fileName} #${hash}`;\n const media = kind === \"image\" ? client.appAssetLibraryImages : client.appAssetLibraryVideos;\n\n const filter = { filter: { referenceName } };\n const existing: Array<{ id: string; attributes: { category?: string; state?: AppAssetLibraryAssetState } }> =\n kind === \"image\"\n ? await client.appAssetLibraries.listImages(libraryId, filter)\n : await client.appAssetLibraries.listVideos(libraryId, filter);\n const reusable = existing.find(\n (a) => a.attributes.category === category && a.attributes.state && READY_STATES.includes(a.attributes.state)\n );\n if (reusable) {\n return { kind, id: reusable.id, state: reusable.attributes.state!, reused: true };\n }\n\n const reserved =\n kind === \"image\"\n ? await client.appAssetLibraryImages.create({ libraryId, fileName, fileSize: data.length, category, referenceName })\n : await client.appAssetLibraryVideos.create({\n libraryId,\n fileName,\n fileSize: data.length,\n category,\n referenceName,\n previewFrameTimeCode: options.previewFrameTimeCode,\n });\n\n await runUploadOperations(reserved.attributes.uploadOperations ?? [], data);\n await media.update(reserved.id, { uploaded: true });\n options.log?.(`uploaded ${fileName} (${kind}, ${data.length} bytes)`);\n\n const state = await waitForAssetReady(\n () => media.get(reserved.id),\n options.pollIntervalMs ?? 3000,\n options.timeoutMs ?? (kind === \"video\" ? 30 * 60_000 : 5 * 60_000)\n );\n return { kind, id: reserved.id, state, reused: false };\n}\n\nexport async function waitForAssetReady(\n get: () => Promise<{ attributes: { state?: AppAssetLibraryAssetState; stateDetails?: Array<{ code?: string; message?: string }> | null } }>,\n intervalMs: number,\n timeoutMs: number\n): Promise<AppAssetLibraryAssetState> {\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const asset = await get();\n const state = asset.attributes.state;\n if (state === \"FAILED\") {\n const why = (asset.attributes.stateDetails ?? []).map((d) => d.message ?? d.code).filter(Boolean).join(\"; \");\n throw new Error(`Asset processing failed${why ? `: ${why}` : \"\"}`);\n }\n if (state && READY_STATES.includes(state)) return state;\n if (Date.now() > deadline) throw new Error(`Asset still ${state ?? \"unknown\"} after ${timeoutMs / 1000}s`);\n await new Promise((r) => setTimeout(r, intervalMs));\n }\n}\n\n// ── Placing a folder of assets on App Store version localizations ──────────\n\ninterface PlannedFile {\n filePath: string;\n placementType: AppAssetLibraryPlacementType;\n groups: string[];\n}\n\nasync function listFiles(dir: string): Promise<string[]> {\n return (await readdir(dir)).filter((f) => !f.startsWith(\".\")).sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));\n}\n\nasync function isDir(path: string): Promise<boolean> {\n return (await stat(path)).isDirectory();\n}\n\n/** Read `<locale>/<folder>/[<GROUP>/]file` and decide where each file goes. */\nasync function planLocale(\n localeDir: string,\n refData: AppAssetLibraryRefDatumAttributes,\n feature: AppAssetLibraryFeature,\n folders: Record<string, AppAssetLibraryPlacementType>,\n warn: (line: string) => void\n): Promise<PlannedFile[]> {\n const planned: PlannedFile[] = [];\n for (const [folder, placementType] of Object.entries(folders)) {\n const typeDir = join(localeDir, folder);\n if (!existsSync(typeDir)) continue;\n const known = new Set(groupsForFeature(refData, feature, placementType));\n\n const entries: Array<{ filePath: string; group?: string }> = [];\n for (const entry of await listFiles(typeDir)) {\n const full = join(typeDir, entry);\n if (await isDir(full)) {\n if (!known.has(entry)) {\n warn(`${relative(localeDir, full)}: \"${entry}\" is not a ${placementType} placement group for ${feature} — skipped`);\n continue;\n }\n for (const f of await listFiles(full)) entries.push({ filePath: join(full, f), group: entry });\n } else {\n entries.push({ filePath: full });\n }\n }\n\n for (const { filePath, group } of entries) {\n const ext = extname(filePath).toLowerCase();\n const isVideo = VIDEO_EXTENSIONS.includes(ext);\n if (!isVideo && !IMAGE_EXTENSIONS.includes(ext)) continue;\n const needsVideo = placementType === \"APP_PREVIEW\";\n const needsImage = placementType === \"APP_SCREENSHOT\" || placementType === \"IMESSAGE_APP_SCREENSHOT\";\n if ((needsVideo && !isVideo) || (needsImage && isVideo)) {\n warn(`${relative(localeDir, filePath)}: ${isVideo ? \"video\" : \"image\"} cannot be a ${placementType} — skipped`);\n continue;\n }\n if (group) {\n planned.push({ filePath, placementType, groups: [group] });\n continue;\n }\n if (isVideo) {\n if (known.size === 1) planned.push({ filePath, placementType, groups: [...known] });\n else warn(`${relative(localeDir, filePath)}: put videos in a placement-group folder (one of ${[...known].join(\", \")}) — skipped`);\n continue;\n }\n const size = readImageSize(await readFile(filePath));\n if (!size) {\n warn(`${relative(localeDir, filePath)}: could not read image size — skipped`);\n continue;\n }\n const { groups, spec } = resolveImageGroups(refData, feature, placementType, size);\n if (!groups.length) {\n warn(`${relative(localeDir, filePath)}: ${size.width}×${size.height} matches no ${placementType} spec — skipped`);\n continue;\n }\n if (size.alpha && spec && spec.alphaAllowed === false) {\n warn(`${relative(localeDir, filePath)}: has an alpha channel, which Apple rejects for this spec`);\n }\n // A size can fit several groups (2732×2048 is both IPAD_13 and IPAD_129).\n // Apple lists the largest device first; place there once. A group folder\n // places it anywhere else on purpose.\n planned.push({ filePath, placementType, groups: groups.slice(0, 1) });\n }\n }\n return planned;\n}\n\nexport interface PlaceAssetsResult {\n uploaded: number;\n reused: number;\n placed: number;\n removed: number;\n warnings: string[];\n}\n\n/**\n * Upload a folder of screenshots, previews and creative assets (product page\n * header, search results) into the app's asset library and place them on each\n * App Store version localization. See ASSET_FOLDERS for the layout.\n *\n * With `overwrite`, existing placements of each (type, group) we upload into\n * are removed first, so the folder becomes the source of truth. Without it,\n * new placements are added and files already placed are left alone.\n */\nexport async function uploadAssetLibrary(options: {\n client: AppStoreConnectClient;\n appId: string;\n versionId: string;\n assetsPath: string;\n overwrite?: boolean;\n /** Override the folder → placement type map (e.g. screenshots-only from a legacy screenshots path). */\n folders?: Record<string, AppAssetLibraryPlacementType>;\n /** Treat files directly under `<locale>/` as this placement type (legacy screenshots layout). */\n rootPlacementType?: AppAssetLibraryPlacementType;\n log?: (line: string) => void;\n}): Promise<PlaceAssetsResult> {\n const { client } = options;\n const log = options.log ?? (() => {});\n const feature: AppAssetLibraryFeature = \"APP_STORE_VERSIONS\";\n const result: PlaceAssetsResult = { uploaded: 0, reused: 0, placed: 0, removed: 0, warnings: [] };\n const warn = (line: string) => {\n result.warnings.push(line);\n log(`warning: ${line}`);\n };\n\n const [library, refData, localizations] = await Promise.all([\n client.appAssetLibraries.getForApp(options.appId),\n client.appAssetLibraries.refData({ features: [feature] }),\n client.appStoreVersions.getLocalizations(options.versionId),\n ]);\n const folders = { ...(options.folders ?? ASSET_FOLDERS) };\n if (options.rootPlacementType) folders[\".\"] = options.rootPlacementType;\n\n // Same file in several locales is uploaded once.\n const uploads = new Map<string, Promise<UploadedAsset>>();\n const uploadOnce = (filePath: string, placementType: AppAssetLibraryPlacementType) => {\n const key = `${filePath}|${categoryFor(placementType)}`;\n if (!uploads.has(key)) {\n uploads.set(\n key,\n uploadLibraryAsset({\n client,\n libraryId: library.id,\n filePath,\n category: categoryFor(placementType),\n referenceName: relative(options.assetsPath, filePath),\n log,\n }).then((a) => {\n if (a.reused) result.reused++;\n else result.uploaded++;\n return a;\n })\n );\n }\n return uploads.get(key)!;\n };\n\n for (const loc of localizations) {\n const localeDir = join(options.assetsPath, loc.attributes.locale);\n if (!existsSync(localeDir)) continue;\n const target: PlacementTarget = { kind: \"appStoreVersionLocalization\", id: loc.id };\n const plan = await planLocale(localeDir, refData, feature, folders, warn);\n\n // Group the plan by (type, group) so limits, overwrite and ordering apply per slot.\n const slots = new Map<string, { placementType: AppAssetLibraryPlacementType; group: string; files: string[] }>();\n for (const p of plan) {\n for (const group of p.groups) {\n const key = `${p.placementType}|${group}`;\n if (!slots.has(key)) slots.set(key, { placementType: p.placementType, group, files: [] });\n slots.get(key)!.files.push(p.filePath);\n }\n }\n\n for (const slot of slots.values()) {\n const where = `${loc.attributes.locale} ${slot.placementType} ${slot.group}`;\n const max = maxCountFor(refData, feature, slot.placementType, slot.group);\n if (max !== undefined && slot.files.length > max) {\n warn(`${where}: ${slot.files.length} files but Apple allows ${max} — keeping the first ${max}`);\n slot.files = slot.files.slice(0, max);\n }\n\n const existing = await client.appAssetLibraryPlacements.listForTarget(target, {\n placementType: slot.placementType,\n placementGroup: slot.group,\n include: \"image,video\",\n });\n if (options.overwrite) {\n for (const p of existing) {\n await client.appAssetLibraryPlacements.delete(p.id);\n result.removed++;\n }\n }\n const kept = options.overwrite ? [] : existing;\n const keptAssetIds = new Set(kept.map((p) => placementAssetId(p)).filter(Boolean));\n\n const ours: string[] = [];\n for (const filePath of slot.files) {\n const asset = await uploadOnce(filePath, slot.placementType);\n if (keptAssetIds.has(asset.id)) continue;\n const placement = await client.appAssetLibraryPlacements.create({\n placementType: slot.placementType,\n placementGroup: slot.group,\n ...(asset.kind === \"image\" ? { imageId: asset.id } : { videoId: asset.id }),\n target,\n });\n ours.push(placement.id);\n result.placed++;\n }\n log(`${where}: placed ${ours.length}${kept.length ? `, kept ${kept.length}` : \"\"}`);\n\n const orderable = slot.placementType === \"APP_SCREENSHOT\" || slot.placementType === \"APP_PREVIEW\" || slot.placementType === \"IMESSAGE_APP_SCREENSHOT\";\n if (orderable && ours.length + kept.length > 1) {\n await client.appAssetLibraryPlacements.order({\n placementGroup: slot.group,\n placementIds: [...ours, ...kept.map((p) => p.id)],\n target,\n });\n }\n }\n }\n return result;\n}\n\nfunction placementAssetId(p: { relationships?: Record<string, { data: unknown }> }): string | undefined {\n for (const rel of [\"image\", \"video\"]) {\n const data = p.relationships?.[rel]?.data as { id?: string } | null | undefined;\n if (data?.id) return data.id;\n }\n return undefined;\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile, readdir, stat } from \"node:fs/promises\";\nimport { join, extname } from \"node:path\";\nimport { createHash } from \"node:crypto\";\nimport type { AppStoreConnectClient } from \"../client/index.js\";\nimport type { Platform, ReleaseType } from \"../types/index.js\";\nimport { loadMetadata } from \"./metadata.js\";\nimport { runUploadOperations, uploadAssetLibrary } from \"./assets.js\";\n\nexport { loadMetadata } from \"./metadata.js\";\nexport type { LocalizedMetadata, MetadataSet } from \"./metadata.js\";\nexport {\n ASSET_FOLDERS,\n uploadAssetLibrary,\n uploadLibraryAsset,\n resolveImageGroups,\n readImageSize,\n categoryFor,\n} from \"./assets.js\";\nexport type { PlaceAssetsResult, UploadedAsset } from \"./assets.js\";\n\nexport interface DeliverOptions {\n client: AppStoreConnectClient;\n bundleIdentifier: string;\n appVersion?: string;\n platform?: Platform;\n ipaPath?: string;\n pkgPath?: string;\n metadataPath?: string;\n screenshotsPath?: string;\n submitForReview?: boolean;\n automaticRelease?: boolean;\n releaseType?: ReleaseType;\n skipBinaryUpload?: boolean;\n skipMetadata?: boolean;\n skipScreenshots?: boolean;\n /**\n * App Asset Library folder: `<locale>/{screenshots,previews,header,search_results}/…`.\n * Places screenshots, previews and creative assets (product page header,\n * search results) on the version. See ASSET_FOLDERS.\n */\n assetsPath?: string;\n /** Route `screenshotsPath` through the asset library instead of the deprecated screenshot sets. */\n useAssetLibrary?: boolean;\n /** Replace existing placements in each slot we upload into (fastlane's overwrite_screenshots). */\n overwriteAssets?: boolean;\n skipAssets?: boolean;\n force?: boolean;\n apiKeyId?: string;\n apiIssuerId?: string;\n apiPrivateKey?: string;\n copyright?: string;\n onOutput?: (chunk: string) => void;\n}\n\nexport interface DeliverResult {\n appId: string;\n versionId: string;\n submitted: boolean;\n}\n\nexport async function uploadToAppStore(options: DeliverOptions): Promise<DeliverResult> {\n const platform = options.platform ?? \"IOS\";\n\n // Find app\n const app = await options.client.apps.findByBundleId(options.bundleIdentifier);\n if (!app) throw new Error(`App not found: ${options.bundleIdentifier}`);\n\n // Find or create version\n const versions = await options.client.appStoreVersions.listForApp(app.id, {\n filter: { platform },\n });\n\n let version = versions.find(\n (v) =>\n v.attributes.appStoreState === \"PREPARE_FOR_SUBMISSION\" ||\n v.attributes.appStoreState === \"DEVELOPER_REJECTED\"\n );\n\n if (!version && options.appVersion) {\n version = await options.client.appStoreVersions.create({\n appId: app.id,\n versionString: options.appVersion,\n platform,\n releaseType: options.releaseType,\n });\n }\n\n if (!version) {\n throw new Error(\"No editable app store version found. Pass appVersion to create one.\");\n }\n\n // Upload metadata\n if (!options.skipMetadata && options.metadataPath && existsSync(options.metadataPath)) {\n await uploadMetadata({\n client: options.client,\n appId: app.id,\n versionId: version.id,\n metadataPath: options.metadataPath,\n });\n }\n\n // Set copyright\n if (options.copyright) {\n await options.client.appStoreVersions.update(version.id, {\n copyright: options.copyright,\n });\n }\n\n const log = (line: string) => options.onOutput?.(`${line}\\n`);\n\n // Upload screenshots\n if (!options.skipScreenshots && options.screenshotsPath && existsSync(options.screenshotsPath)) {\n if (options.useAssetLibrary) {\n await uploadAssetLibrary({\n client: options.client,\n appId: app.id,\n versionId: version.id,\n assetsPath: options.screenshotsPath,\n folders: {},\n rootPlacementType: \"APP_SCREENSHOT\",\n overwrite: options.overwriteAssets,\n log,\n });\n } else {\n await uploadScreenshots({\n client: options.client,\n versionId: version.id,\n screenshotsPath: options.screenshotsPath,\n });\n }\n }\n\n // Upload asset library media: screenshots, previews, header, search results\n if (!options.skipAssets && options.assetsPath && existsSync(options.assetsPath)) {\n await uploadAssetLibrary({\n client: options.client,\n appId: app.id,\n versionId: version.id,\n assetsPath: options.assetsPath,\n overwrite: options.overwriteAssets,\n log,\n });\n }\n\n // Upload binary\n if (!options.skipBinaryUpload) {\n const binaryPath = options.ipaPath ?? options.pkgPath;\n if (binaryPath && options.apiKeyId && options.apiIssuerId) {\n const { uploadWithAltool } = await import(\"../xcode/upload.js\");\n await uploadWithAltool({\n filePath: binaryPath,\n apiKeyId: options.apiKeyId,\n apiIssuerId: options.apiIssuerId,\n apiPrivateKey: options.apiPrivateKey,\n onOutput: options.onOutput,\n });\n }\n }\n\n // Submit for review\n let submitted = false;\n if (options.submitForReview) {\n await submitForReview({\n client: options.client,\n appId: app.id,\n versionId: version.id,\n });\n submitted = true;\n }\n\n return { appId: app.id, versionId: version.id, submitted };\n}\n\nexport async function submitForReview(options: {\n client: AppStoreConnectClient;\n appId: string;\n versionId: string;\n}): Promise<void> {\n await options.client.reviewSubmissions.submitVersion(options.versionId);\n}\n\nexport async function uploadMetadata(options: {\n client: AppStoreConnectClient;\n appId: string;\n versionId: string;\n metadataPath: string;\n}): Promise<void> {\n const metadata = await loadMetadata(options.metadataPath);\n\n // Get existing localizations\n const existingLocs = await options.client.appStoreVersions.getLocalizations(options.versionId);\n\n for (const loc of metadata.localizations) {\n const existing = existingLocs.find((e) => e.attributes.locale === loc.locale);\n const attrs: Record<string, string | undefined> = {};\n if (loc.description) attrs.description = loc.description;\n if (loc.keywords) attrs.keywords = loc.keywords;\n if (loc.releaseNotes) attrs.whatsNew = loc.releaseNotes;\n if (loc.supportUrl) attrs.supportUrl = loc.supportUrl;\n if (loc.marketingUrl) attrs.marketingUrl = loc.marketingUrl;\n if (loc.promotionalText) attrs.promotionalText = loc.promotionalText;\n\n if (existing) {\n await options.client.appStoreVersions.updateLocalization(existing.id, attrs);\n } else {\n await options.client.appStoreVersions.createLocalization({\n versionId: options.versionId,\n locale: loc.locale,\n ...attrs,\n });\n }\n }\n\n // Update copyright\n if (metadata.copyright) {\n await options.client.appStoreVersions.update(options.versionId, {\n copyright: metadata.copyright,\n });\n }\n}\n\n/**\n * Legacy screenshot-set upload. Apple deprecated screenshot sets in ASC API\n * 4.5.1 — prefer `uploadAssetLibrary` (or `useAssetLibrary: true`).\n */\nexport async function uploadScreenshots(options: {\n client: AppStoreConnectClient;\n versionId: string;\n screenshotsPath: string;\n}): Promise<void> {\n const localizations = await options.client.appStoreVersions.getLocalizations(options.versionId);\n\n for (const loc of localizations) {\n const localeDir = join(options.screenshotsPath, loc.attributes.locale);\n if (!existsSync(localeDir)) continue;\n\n const sets = await options.client.appScreenshots.listSetsForLocalization(loc.id);\n const files = (await readdir(localeDir)).filter((f) =>\n [\".png\", \".jpg\", \".jpeg\"].includes(extname(f).toLowerCase())\n );\n\n for (const file of files) {\n const filePath = join(localeDir, file);\n const fileData = await readFile(filePath);\n const checksum = createHash(\"md5\").update(fileData).digest(\"hex\");\n\n // Determine display type from filename convention\n const displayType = detectDisplayType(file);\n if (!displayType) continue;\n\n // Find or create screenshot set\n let set = sets.find((s) => s.attributes.screenshotDisplayType === displayType);\n if (!set) {\n set = await options.client.appScreenshots.createSet({\n localizationId: loc.id,\n screenshotDisplayType: displayType,\n });\n }\n\n // Reserve, upload, commit\n const reserved = await options.client.appScreenshots.reserveScreenshot({\n setId: set.id,\n fileName: file,\n fileSize: fileData.length,\n });\n\n await runUploadOperations(reserved.attributes.uploadOperations ?? [], fileData);\n\n await options.client.appScreenshots.commitScreenshot(reserved.id, {\n sourceFileChecksum: checksum,\n uploaded: true,\n });\n }\n }\n}\n\nfunction detectDisplayType(filename: string): string | null {\n const lower = filename.toLowerCase();\n if (lower.includes(\"6.7\") || lower.includes(\"iphone_67\")) return \"APP_IPHONE_67\";\n if (lower.includes(\"6.5\") || lower.includes(\"iphone_65\")) return \"APP_IPHONE_65\";\n if (lower.includes(\"5.5\") || lower.includes(\"iphone_55\")) return \"APP_IPHONE_55\";\n if (lower.includes(\"ipad_pro_3gen\") || lower.includes(\"12.9\")) return \"APP_IPAD_PRO_3GEN_129\";\n if (lower.includes(\"ipad_pro\") || lower.includes(\"ipad\")) return \"APP_IPAD_PRO_129\";\n return null;\n}\n"]}
|
|
@@ -16,5 +16,12 @@ type BetaReviewState = "WAITING_FOR_REVIEW" | "IN_REVIEW" | "REJECTED" | "APPROV
|
|
|
16
16
|
type ExportMethod = "app-store" | "ad-hoc" | "development" | "enterprise" | "validation" | "package" | "developer-id";
|
|
17
17
|
type AppStoreVersionState = "ACCEPTED" | "DEVELOPER_REJECTED" | "DEVELOPER_REMOVED_FROM_SALE" | "IN_REVIEW" | "INVALID_BINARY" | "METADATA_REJECTED" | "PENDING_APPLE_RELEASE" | "PENDING_CONTRACT" | "PENDING_DEVELOPER_RELEASE" | "PREPARE_FOR_SUBMISSION" | "PREORDER_READY_FOR_SALE" | "PROCESSING_FOR_APP_STORE" | "READY_FOR_REVIEW" | "READY_FOR_SALE" | "REJECTED" | "REMOVED_FROM_SALE" | "WAITING_FOR_EXPORT_COMPLIANCE" | "WAITING_FOR_REVIEW" | "REPLACED_WITH_NEW_VERSION" | "NOT_APPLICABLE";
|
|
18
18
|
type ReleaseType = "MANUAL" | "AFTER_APPROVAL" | "SCHEDULED";
|
|
19
|
+
type AppAssetLibraryAssetCategory = "APP_SCREENSHOTS_AND_PREVIEWS" | "CREATIVE_ASSETS";
|
|
20
|
+
type AppAssetLibraryMediaType = "IMAGE" | "VIDEO";
|
|
21
|
+
type AppAssetLibraryPlacementType = "APP_SCREENSHOT" | "IMESSAGE_APP_SCREENSHOT" | "APP_PREVIEW" | "PRODUCT_PAGE_HEADER_ASSET" | "APP_STORE_SEARCH_RESULTS_ASSET" | "SEARCH_RESULTS_ADS_ASSET" | "TODAY_TAB_ADS_ASSET" | "EVENT_CARD_ASSET" | "EVENT_DETAILS_PAGE_ASSET" | "RETENTION_MESSAGE_ASSET";
|
|
22
|
+
type AppAssetLibraryAssetState = "AWAITING_UPLOAD" | "UPLOAD_COMPLETE" | "FAILED" | "COMPLETE" | "PREPARE_FOR_SUBMISSION" | "READY_FOR_REVIEW" | "WAITING_FOR_REVIEW" | "IN_REVIEW" | "ACCEPTED" | "APPROVED" | "REJECTED" | "ARCHIVED";
|
|
23
|
+
type AppAssetLibraryPlacementState = "ASSET_PROCESSING" | "FAILED" | "PARENT_PREPARE_FOR_SUBMISSION" | "PARENT_READY_FOR_REVIEW" | "PARENT_WAITING_FOR_REVIEW" | "PARENT_IN_REVIEW" | "PARENT_APPROVED";
|
|
24
|
+
type AppAssetLibraryFeature = "APP_STORE_VERSIONS" | "CUSTOM_PRODUCT_PAGES" | "PRODUCT_PAGE_OPTIMIZATIONS" | "IN_APP_EVENTS" | "IN_APP_PURCHASES" | "SUBSCRIPTIONS" | "RETENTION_MESSAGING" | "GAME_CENTER" | "APP_CLIPS" | "APPLE_ADS";
|
|
25
|
+
type AppAssetLibraryPlacementPlatform = "IPHONE_APP_STORE" | "IPAD_APP_STORE" | "WATCH_APP_STORE" | "IMESSAGE_APP_STORE" | "VISION_PRO_APP_STORE" | "MAC_APP_STORE" | "TV_APP_STORE" | "ANY";
|
|
19
26
|
|
|
20
|
-
export type { AppStoreVersionState as A, BundleIdPlatform as B, CertificateType as C, DeviceClass as D, ExportMethod as E, ProfileType as P, ReleaseType as R, ProfileState as a, Platform as b, DeviceStatus as c, CapabilityType as d, CapabilitySettingsKey as e, CapabilityOptionKey as f, ContentRightsDeclaration as g, BuildProcessingState as h, BetaReviewState as i };
|
|
27
|
+
export type { AppStoreVersionState as A, BundleIdPlatform as B, CertificateType as C, DeviceClass as D, ExportMethod as E, ProfileType as P, ReleaseType as R, ProfileState as a, Platform as b, DeviceStatus as c, CapabilityType as d, CapabilitySettingsKey as e, CapabilityOptionKey as f, ContentRightsDeclaration as g, BuildProcessingState as h, BetaReviewState as i, AppAssetLibraryAssetCategory as j, AppAssetLibraryMediaType as k, AppAssetLibraryPlacementType as l, AppAssetLibraryAssetState as m, AppAssetLibraryPlacementState as n, AppAssetLibraryFeature as o, AppAssetLibraryPlacementPlatform as p };
|
|
@@ -16,5 +16,12 @@ type BetaReviewState = "WAITING_FOR_REVIEW" | "IN_REVIEW" | "REJECTED" | "APPROV
|
|
|
16
16
|
type ExportMethod = "app-store" | "ad-hoc" | "development" | "enterprise" | "validation" | "package" | "developer-id";
|
|
17
17
|
type AppStoreVersionState = "ACCEPTED" | "DEVELOPER_REJECTED" | "DEVELOPER_REMOVED_FROM_SALE" | "IN_REVIEW" | "INVALID_BINARY" | "METADATA_REJECTED" | "PENDING_APPLE_RELEASE" | "PENDING_CONTRACT" | "PENDING_DEVELOPER_RELEASE" | "PREPARE_FOR_SUBMISSION" | "PREORDER_READY_FOR_SALE" | "PROCESSING_FOR_APP_STORE" | "READY_FOR_REVIEW" | "READY_FOR_SALE" | "REJECTED" | "REMOVED_FROM_SALE" | "WAITING_FOR_EXPORT_COMPLIANCE" | "WAITING_FOR_REVIEW" | "REPLACED_WITH_NEW_VERSION" | "NOT_APPLICABLE";
|
|
18
18
|
type ReleaseType = "MANUAL" | "AFTER_APPROVAL" | "SCHEDULED";
|
|
19
|
+
type AppAssetLibraryAssetCategory = "APP_SCREENSHOTS_AND_PREVIEWS" | "CREATIVE_ASSETS";
|
|
20
|
+
type AppAssetLibraryMediaType = "IMAGE" | "VIDEO";
|
|
21
|
+
type AppAssetLibraryPlacementType = "APP_SCREENSHOT" | "IMESSAGE_APP_SCREENSHOT" | "APP_PREVIEW" | "PRODUCT_PAGE_HEADER_ASSET" | "APP_STORE_SEARCH_RESULTS_ASSET" | "SEARCH_RESULTS_ADS_ASSET" | "TODAY_TAB_ADS_ASSET" | "EVENT_CARD_ASSET" | "EVENT_DETAILS_PAGE_ASSET" | "RETENTION_MESSAGE_ASSET";
|
|
22
|
+
type AppAssetLibraryAssetState = "AWAITING_UPLOAD" | "UPLOAD_COMPLETE" | "FAILED" | "COMPLETE" | "PREPARE_FOR_SUBMISSION" | "READY_FOR_REVIEW" | "WAITING_FOR_REVIEW" | "IN_REVIEW" | "ACCEPTED" | "APPROVED" | "REJECTED" | "ARCHIVED";
|
|
23
|
+
type AppAssetLibraryPlacementState = "ASSET_PROCESSING" | "FAILED" | "PARENT_PREPARE_FOR_SUBMISSION" | "PARENT_READY_FOR_REVIEW" | "PARENT_WAITING_FOR_REVIEW" | "PARENT_IN_REVIEW" | "PARENT_APPROVED";
|
|
24
|
+
type AppAssetLibraryFeature = "APP_STORE_VERSIONS" | "CUSTOM_PRODUCT_PAGES" | "PRODUCT_PAGE_OPTIMIZATIONS" | "IN_APP_EVENTS" | "IN_APP_PURCHASES" | "SUBSCRIPTIONS" | "RETENTION_MESSAGING" | "GAME_CENTER" | "APP_CLIPS" | "APPLE_ADS";
|
|
25
|
+
type AppAssetLibraryPlacementPlatform = "IPHONE_APP_STORE" | "IPAD_APP_STORE" | "WATCH_APP_STORE" | "IMESSAGE_APP_STORE" | "VISION_PRO_APP_STORE" | "MAC_APP_STORE" | "TV_APP_STORE" | "ANY";
|
|
19
26
|
|
|
20
|
-
export type { AppStoreVersionState as A, BundleIdPlatform as B, CertificateType as C, DeviceClass as D, ExportMethod as E, ProfileType as P, ReleaseType as R, ProfileState as a, Platform as b, DeviceStatus as c, CapabilityType as d, CapabilitySettingsKey as e, CapabilityOptionKey as f, ContentRightsDeclaration as g, BuildProcessingState as h, BetaReviewState as i };
|
|
27
|
+
export type { AppStoreVersionState as A, BundleIdPlatform as B, CertificateType as C, DeviceClass as D, ExportMethod as E, ProfileType as P, ReleaseType as R, ProfileState as a, Platform as b, DeviceStatus as c, CapabilityType as d, CapabilitySettingsKey as e, CapabilityOptionKey as f, ContentRightsDeclaration as g, BuildProcessingState as h, BetaReviewState as i, AppAssetLibraryAssetCategory as j, AppAssetLibraryMediaType as k, AppAssetLibraryPlacementType as l, AppAssetLibraryAssetState as m, AppAssetLibraryPlacementState as n, AppAssetLibraryFeature as o, AppAssetLibraryPlacementPlatform as p };
|