0f127dbc70
- 删除 coverImagePart:各 E2E 脚本都有自己的本地实现,仓库内无人导入 - COVER_PNG 只作 imagePart 的默认值,收回 export
83 lines
2.9 KiB
JavaScript
83 lines
2.9 KiB
JavaScript
// 游戏分发 E2E 脚本共用的 multipart 发布 helper。
|
||
//
|
||
// 这些脚本都直连 api-server,发布口是同一套契约:`metadata` JSON 文本 part + 可选 `cover`
|
||
// 二进制 part + 按顺序重复的 `screenshot` 二进制 part;各自的 `api()` 也只在 body 形态上分支。
|
||
// 这里收敛这段稳定契约,脚本只保留自己的路径、鉴权头与返回形状差异。
|
||
|
||
/** 1x1 透明 PNG:仅用于满足发布必填的封面/截图 part,内容不参与断言。 */
|
||
const COVER_PNG = Buffer.from(
|
||
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==',
|
||
'base64',
|
||
);
|
||
|
||
/**
|
||
* 发布用图片 part。
|
||
*
|
||
* 默认文件名 `<kind>-<id>.png`、`image/png`;脚本可通过 `options.fileName` 保留自己的前缀,
|
||
* 或用 `options.bytes` / `options.contentType` 覆盖字节与类型。
|
||
*/
|
||
export function imagePart(kind, id, options = {}) {
|
||
const {
|
||
bytes = COVER_PNG,
|
||
fileName = `${kind}-${id}.png`,
|
||
contentType = 'image/png',
|
||
} = options;
|
||
return { bytes, fileName, contentType };
|
||
}
|
||
|
||
/**
|
||
* 组装发布请求体:`metadata` 文本 part + 可选 `cover` / 按顺序重复的 `screenshot` 二进制 part。
|
||
*
|
||
* `metadata.screenshots` 里的 `null` 槽位按出现顺序消费 `screenshots` 数组里的 part;string
|
||
* 槽位沿用该 objectKey。调用方负责保证 null 槽位数量与 part 数量一致(不一致服务端会 400)。
|
||
*/
|
||
export function publishFormData(metadata, { cover, screenshots = [] } = {}) {
|
||
const form = new FormData();
|
||
form.append('metadata', JSON.stringify(metadata));
|
||
if (cover) {
|
||
form.append(
|
||
'cover',
|
||
new Blob([cover.bytes], { type: cover.contentType }),
|
||
cover.fileName,
|
||
);
|
||
}
|
||
for (const screenshot of screenshots) {
|
||
if (!screenshot) continue;
|
||
form.append(
|
||
'screenshot',
|
||
new Blob([screenshot.bytes], { type: screenshot.contentType }),
|
||
screenshot.fileName,
|
||
);
|
||
}
|
||
return form;
|
||
}
|
||
|
||
/**
|
||
* 推导 `api()` 的最终请求头与请求体。
|
||
*
|
||
* - `formData`:multipart/form-data,不手动设 `Content-Type`,交给 fetch 生成 boundary。
|
||
* - `binary`:直接作为 body(例如分片 PUT 的字节)。
|
||
* - `body !== undefined`:按 JSON 序列化,并补 `Content-Type: application/json`。
|
||
*
|
||
* 调用方先自行合并 `{ ...ENVELOPE, ...headers }` 与 `Authorization`,再把结果作为 `headers`
|
||
* 传进来;返回值里的 `headers` 是补完 `Content-Type` 后的副本。
|
||
*/
|
||
export function resolveApiRequest({
|
||
formData,
|
||
binary,
|
||
body,
|
||
headers = {},
|
||
} = {}) {
|
||
const finalHeaders = { ...headers };
|
||
let finalBody;
|
||
if (formData) {
|
||
finalBody = formData;
|
||
} else if (binary) {
|
||
finalBody = binary;
|
||
} else if (body !== undefined) {
|
||
finalHeaders['Content-Type'] = 'application/json';
|
||
finalBody = JSON.stringify(body);
|
||
}
|
||
return { headers: finalHeaders, body: finalBody };
|
||
}
|