Some checks failed
Build & Release APK / build (push) Has been cancelled
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WontRuPqKcod9XK4ZN9MXv
51 lines
2.2 KiB
JavaScript
51 lines
2.2 KiB
JavaScript
#!/usr/bin/env node
|
|
// Minimal App Store Connect API client (ES256 JWT via node:crypto, no deps).
|
|
//
|
|
// node store/asc.js get /v1/apps/6809350427
|
|
// node store/asc.js patch /v1/appInfos/ID '{"data":{...}}'
|
|
//
|
|
// Reads the key from eas.json submit.production.ios (ascApiKeyPath/Id/IssuerId).
|
|
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const crypto = require("crypto");
|
|
|
|
const eas = JSON.parse(fs.readFileSync(path.join(__dirname, "..", "eas.json"), "utf8"));
|
|
const cfg = eas.submit.production.ios;
|
|
const APP_ID = cfg.ascAppId;
|
|
const BASE = "https://api.appstoreconnect.apple.com";
|
|
|
|
function b64url(buf) {
|
|
return Buffer.from(buf).toString("base64").replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
}
|
|
|
|
function token() {
|
|
const now = Math.floor(Date.now() / 1000);
|
|
const header = b64url(JSON.stringify({ alg: "ES256", kid: cfg.ascApiKeyId, typ: "JWT" }));
|
|
const payload = b64url(JSON.stringify({ iss: cfg.ascApiKeyIssuerId, iat: now, exp: now + 19 * 60, aud: "appstoreconnect-v1" }));
|
|
const key = fs.readFileSync(cfg.ascApiKeyPath, "utf8");
|
|
const sig = crypto.sign("sha256", Buffer.from(`${header}.${payload}`), { key, dsaEncoding: "ieee-p1363" });
|
|
return `${header}.${payload}.${b64url(sig)}`;
|
|
}
|
|
|
|
async function api(method, p, body, extraHeaders = {}) {
|
|
const res = await fetch(p.startsWith("http") ? p : BASE + p, {
|
|
method,
|
|
headers: { Authorization: `Bearer ${token()}`, "Content-Type": "application/json", ...extraHeaders },
|
|
body: body === undefined ? undefined : typeof body === "string" ? body : JSON.stringify(body),
|
|
});
|
|
const text = await res.text();
|
|
let json;
|
|
try { json = text ? JSON.parse(text) : null; } catch { json = text; }
|
|
if (!res.ok) throw new Error(`${method} ${p} -> ${res.status}\n${JSON.stringify(json, null, 2)}`);
|
|
return json;
|
|
}
|
|
|
|
module.exports = { api, APP_ID, token };
|
|
|
|
if (require.main === module) {
|
|
const [, , method, p, body] = process.argv;
|
|
if (!method || !p) { console.error("usage: asc.js <get|post|patch|delete> <path> [json]"); process.exit(1); }
|
|
api(method.toUpperCase(), p, body).then((r) => console.log(JSON.stringify(r, null, 2))).catch((e) => { console.error(e.message); process.exit(1); });
|
|
}
|