Files
wehub-resource-sync e0e362d700
SDK Tests / changes (push) Successful in 2m29s
Real E2E Tests / changes (push) Successful in 2m29s
Deploy Docs Pages / build (push) Has been cancelled
Deploy Docs Pages / deploy (push) Has been cancelled
Real E2E Tests / JavaScript E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Python E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Java E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / C# E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Go E2E (docker bridge) (push) Has been cancelled
Real E2E Tests / Real E2E CI (push) Has been cancelled
SDK Tests / SDK CI (push) Has been cancelled
SDK Tests / CLI Tests (push) Has been cancelled
SDK Tests / Python SDK Quality (code-interpreter) (push) Has been cancelled
SDK Tests / Python SDK Quality (sandbox) (push) Has been cancelled
SDK Tests / Python SDK Tests (code-interpreter) (push) Has been cancelled
SDK Tests / JavaScript SDK Quality And Tests (code-interpreter) (push) Has been cancelled
SDK Tests / JavaScript SDK Quality And Tests (sandbox) (push) Has been cancelled
SDK Tests / Python SDK Tests (sandbox) (push) Has been cancelled
SDK Tests / CLI Quality (push) Has been cancelled
SDK Tests / Kotlin SDK Quality And Tests (sandbox) (push) Has been cancelled
SDK Tests / Kotlin SDK Quality And Tests (code-interpreter) (push) Has been cancelled
SDK Tests / C# SDK Quality And Tests (code-interpreter) (push) Has been cancelled
SDK Tests / C# SDK Quality And Tests (sandbox) (push) Has been cancelled
SDK Tests / Go SDK Quality And Tests (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:39:33 +08:00

151 lines
5.3 KiB
JavaScript

#!/usr/bin/env node
// Copyright 2026 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { spawnSync } from "node:child_process";
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import path from "node:path";
import process from "node:process";
import { fileURLToPath } from "node:url";
const LICENSE_OWNER = "Alibaba Group Holding Ltd.";
const LICENSE_MARKER_REGEX = new RegExp(`Copyright [0-9]{4} ${LICENSE_OWNER}`);
function buildLicenseText() {
const year = new Date().getFullYear();
return `Copyright ${year} ${LICENSE_OWNER}.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.`;
}
function asLineCommentHeader(text) {
return text
.split("\n")
.map((line) => `// ${line}`)
.join("\n");
}
function ensureLicenseHeader(filePath) {
const body = readFileSync(filePath, "utf8");
const head = body.split("\n").slice(0, 40).join("\n");
if (LICENSE_MARKER_REGEX.test(head)) {
return;
}
const header = asLineCommentHeader(buildLicenseText());
writeFileSync(filePath, `${header}\n\n${body}`, "utf8");
}
function fail(message) {
console.error(`❌ ${message}`);
process.exit(1);
}
function run(cmd, args, cwd) {
const pretty = [cmd, ...args].join(" ");
console.log(`\n▶ ${pretty}`);
const res = spawnSync(cmd, args, { cwd, stdio: "inherit" });
if (res.status !== 0) {
fail(`Command failed (exit=${res.status}): ${pretty}`);
}
}
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// scripts/ -> package root
const packageRoot = path.resolve(__dirname, "..");
// scripts/ -> repo root (OpenSandbox/)
const repoRoot = path.resolve(__dirname, "../../../../");
const specs = {
execd: path.join(repoRoot, "specs", "execd-api.yaml"),
egress: path.join(repoRoot, "specs", "egress-api.yaml"),
lifecycle: path.join(repoRoot, "specs", "sandbox-lifecycle.yml"),
};
for (const [name, p] of Object.entries(specs)) {
if (!existsSync(p)) {
fail(`OpenAPI spec not found for '${name}': ${p}`);
}
}
const outDir = path.join(packageRoot, "src", "api");
mkdirSync(outDir, { recursive: true });
const outFiles = {
execd: path.join(outDir, "execd.ts"),
egress: path.join(outDir, "egress.ts"),
lifecycle: path.join(outDir, "lifecycle.ts"),
};
console.log("🚀 OpenSandbox TypeScript SDK API Generator");
console.log(`- repoRoot: ${repoRoot}`);
console.log(`- outDir: ${outDir}`);
// Use pnpm as requested by the project rules.
run("pnpm", ["exec", "openapi-typescript", specs.execd, "-o", outFiles.execd], packageRoot);
run("pnpm", ["exec", "openapi-typescript", specs.egress, "-o", outFiles.egress], packageRoot);
run(
"pnpm",
["exec", "openapi-typescript", specs.lifecycle, "-o", outFiles.lifecycle],
packageRoot,
);
// The generator may overwrite outputs; re-apply unified license headers after generation.
ensureLicenseHeader(outFiles.execd);
ensureLicenseHeader(outFiles.egress);
ensureLicenseHeader(outFiles.lifecycle);
// Clarify that the generated session API in execd.ts is not the recommended entry point.
const EXECD_SESSION_NOTE = `/**
* NOTE: The session-related path types and operations in this file (e.g. /session, runInSession)
* are generated from the execd OpenAPI spec. They are not the recommended runtime entry point.
* Use \`sandbox.commands.createSession()\`, \`sandbox.commands.runInSession()\`, and
* \`sandbox.commands.deleteSession()\` instead.
*/`;
function ensureExecdSessionNote(filePath) {
const body = readFileSync(filePath, "utf8");
if (body.includes("not the recommended runtime entry point")) {
return;
}
// Insert after the first "Do not make direct changes" block (after the first empty line that follows it).
const marker = "Do not make direct changes to the file.";
const idx = body.indexOf(marker);
if (idx === -1) return;
const afterBlock = body.indexOf("\n\n", idx + marker.length);
const insertAt = afterBlock === -1 ? idx + marker.length : afterBlock + 2;
const newBody = body.slice(0, insertAt) + "\n" + EXECD_SESSION_NOTE + "\n" + body.slice(insertAt);
writeFileSync(filePath, newBody, "utf8");
}
ensureExecdSessionNote(outFiles.execd);
console.log("\n✅ API type generation completed:");
console.log(`- ${path.relative(packageRoot, outFiles.execd)}`);
console.log(`- ${path.relative(packageRoot, outFiles.egress)}`);
console.log(`- ${path.relative(packageRoot, outFiles.lifecycle)}`);