#!/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 [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); }); }