Add Cloudflare public cache publisher
This commit is contained in:
@@ -4,7 +4,9 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"build": "tsc -p tsconfig.json --outDir dist",
|
||||||
"check": "tsc --noEmit -p tsconfig.json",
|
"check": "tsc --noEmit -p tsconfig.json",
|
||||||
|
"public-cache:publish": "npm run build && node scripts/publish_public_cache.mjs",
|
||||||
"test": "tsc -p tsconfig.test.json --outDir dist && node --test dist/tests/*.test.js"
|
"test": "tsc -p tsconfig.test.json --outDir dist && node --test dist/tests/*.test.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -0,0 +1,154 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
import { spawn } from "node:child_process";
|
||||||
|
import { readFile, rm, writeFile } from "node:fs/promises";
|
||||||
|
import { tmpdir } from "node:os";
|
||||||
|
import { join, resolve } from "node:path";
|
||||||
|
|
||||||
|
import {
|
||||||
|
parsePluginRegistryDocument,
|
||||||
|
pluginRegistryKvKey,
|
||||||
|
} from "../dist/src/plugin_registry.js";
|
||||||
|
import {
|
||||||
|
parseReleaseManifestDocument,
|
||||||
|
releaseManifestKvKey,
|
||||||
|
} from "../dist/src/release_manifests.js";
|
||||||
|
import {
|
||||||
|
parsePublicSigningKeysDocument,
|
||||||
|
publicSigningKeysKvKey,
|
||||||
|
} from "../dist/src/signing_keys.js";
|
||||||
|
|
||||||
|
const DOCUMENTS = [
|
||||||
|
{
|
||||||
|
flag: "--signing-keys",
|
||||||
|
label: "public signing keys",
|
||||||
|
keyFor: publicSigningKeysKvKey,
|
||||||
|
parse: parsePublicSigningKeysDocument,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
flag: "--plugin-registry",
|
||||||
|
label: "plugin registry",
|
||||||
|
keyFor: pluginRegistryKvKey,
|
||||||
|
parse: parsePluginRegistryDocument,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
flag: "--release-manifest",
|
||||||
|
label: "release manifest",
|
||||||
|
keyFor: releaseManifestKvKey,
|
||||||
|
parse: parseReleaseManifestDocument,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const options = parseArgs(process.argv.slice(2));
|
||||||
|
const publications = DOCUMENTS.flatMap((document) => {
|
||||||
|
const path = options.documents.get(document.flag);
|
||||||
|
return path === undefined ? [] : [{ ...document, path }];
|
||||||
|
});
|
||||||
|
|
||||||
|
if (publications.length === 0) {
|
||||||
|
throw new Error("Provide at least one public cache document path.");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const publication of publications) {
|
||||||
|
await publishDocument(options.environment, publication);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseArgs(args) {
|
||||||
|
const options = {
|
||||||
|
environment: undefined,
|
||||||
|
documents: new Map(),
|
||||||
|
};
|
||||||
|
const flags = new Set(DOCUMENTS.map((document) => document.flag));
|
||||||
|
|
||||||
|
for (let index = 0; index < args.length; index += 1) {
|
||||||
|
const arg = args[index];
|
||||||
|
if (arg === "--help" || arg === "-h") {
|
||||||
|
printUsage();
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
if (arg === "--environment") {
|
||||||
|
options.environment = requiredValue(args, index, arg);
|
||||||
|
index += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (flags.has(arg)) {
|
||||||
|
options.documents.set(arg, requiredValue(args, index, arg));
|
||||||
|
index += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw new Error(`Unknown argument: ${arg}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.environment === undefined) {
|
||||||
|
throw new Error("Missing required --environment value.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
function requiredValue(args, index, flag) {
|
||||||
|
const value = args[index + 1];
|
||||||
|
if (value === undefined || value.startsWith("--")) {
|
||||||
|
throw new Error(`Missing value for ${flag}.`);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function publishDocument(environment, publication) {
|
||||||
|
const sourcePath = resolve(publication.path);
|
||||||
|
const raw = await readFile(sourcePath, "utf8");
|
||||||
|
const document = publication.parse(raw);
|
||||||
|
const kvKey = publication.keyFor(environment);
|
||||||
|
const tempPath = join(tmpdir(), `ely-public-cache-${process.pid}-${Date.now()}.json`);
|
||||||
|
const normalized = `${JSON.stringify(document, null, 2)}\n`;
|
||||||
|
|
||||||
|
await writeFile(tempPath, normalized, { mode: 0o600 });
|
||||||
|
try {
|
||||||
|
await runWrangler([
|
||||||
|
"kv",
|
||||||
|
"key",
|
||||||
|
"put",
|
||||||
|
kvKey,
|
||||||
|
"--binding",
|
||||||
|
"ELY_KV",
|
||||||
|
"--remote",
|
||||||
|
"--path",
|
||||||
|
tempPath,
|
||||||
|
]);
|
||||||
|
console.log(`Published ${publication.label} to ${kvKey}`);
|
||||||
|
} finally {
|
||||||
|
await rm(tempPath, { force: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function runWrangler(args) {
|
||||||
|
return new Promise((resolveProcess, rejectProcess) => {
|
||||||
|
const command = process.platform === "win32" ? "npx.cmd" : "npx";
|
||||||
|
const child = spawn(command, ["wrangler", ...args], {
|
||||||
|
stdio: "inherit",
|
||||||
|
});
|
||||||
|
|
||||||
|
child.on("error", rejectProcess);
|
||||||
|
child.on("exit", (code) => {
|
||||||
|
if (code === 0) {
|
||||||
|
resolveProcess();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rejectProcess(new Error(`wrangler exited with code ${code}`));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function printUsage() {
|
||||||
|
console.log(`Usage:
|
||||||
|
npm run public-cache:publish -- --environment production \\
|
||||||
|
--signing-keys ./secure/signing-keys.json \\
|
||||||
|
--plugin-registry ./secure/plugin-registry.json \\
|
||||||
|
--release-manifest ./secure/release-manifest.json`);
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error(error instanceof Error ? error.message : String(error));
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user