krishnax12/usb-c-control-dial
USB-C control dial PCB with an EC11 push encoder and a 16-LED ring for volume and brightness controls. Work in progress; firmware not included and not fabrication-ready.
- Version
- 0.0.3
- License
- unset
- Stars
- 1
scripts/publish.ts
import { homedir } from "node:os"
import { resolve } from "node:path"
import { isDeepStrictEqual } from "node:util"
import { gzipSync } from "node:zlib"
import { runAllChecks } from "@tscircuit/checks"
import type { AnyCircuitElement } from "circuit-json"
const projectDirectory = resolve(import.meta.dir, "..")
const packageName = "krishnax12/usb-c-control-dial"
const registryUrl = "https://registry-api.tscircuit.com"
const config: { sessionToken: string; accountId: string } = await Bun.file(
resolve(homedir(), ".config/tscircuit-nodejs/config.json"),
).json()
const headers = {
"Content-Type": "application/json",
Authorization: `Bearer ${config.sessionToken}`,
}
async function registryRequest<T>(
endpoint: string,
request: Record<string, unknown>,
): Promise<T> {
const response = await fetch(`${registryUrl}/${endpoint}`, {
method: "POST",
headers,
body: JSON.stringify(request),
signal: AbortSignal.timeout(60_000),
})
if (!response.ok)
throw new Error(`${endpoint} failed: HTTP ${response.status}`)
return response.json()
}
const { account } = await registryRequest<{
account: { tscircuit_handle: string }
}>("accounts/get", { account_id: config.accountId })
if (account.tscircuit_handle.toLowerCase() !== "krishnax12")
throw new Error("Expected the krishnax12 account; publication stopped")
const packageJson: { version: string; description: string } = await Bun.file(
resolve(projectDirectory, "package.json"),
).json()
const nativeCircuit: AnyCircuitElement[] = await Bun.file(
resolve(projectDirectory, "outputs/repro/circuit.json"),
).json()
const embeddedDiagnostics = nativeCircuit.filter((element) =>
/error|warning/.test(element.type),
)
const independentDiagnostics = await runAllChecks(nativeCircuit)
const diagnostics = [...embeddedDiagnostics, ...independentDiagnostics]
if (diagnostics.some((element) => element.type.endsWith("_error")))
throw new Error("Publication stopped: PCB or schematic errors remain")
if (diagnostics.length && !Bun.argv.includes("--allow-warnings"))
throw new Error(
"Publication stopped: warnings remain; --allow-warnings requires explicit approval",
)
if (diagnostics.length)
console.warn("Publishing with visible warnings:", [
...new Set(diagnostics.map((element) => element.type)),
])
await Bun.write(
resolve(projectDirectory, "outputs/repro/independent-checks.json"),
JSON.stringify(independentDiagnostics, null, 2),
)
const verification: { witnesses: object[] } = await Bun.file(
resolve(projectDirectory, "outputs/repro/verification.json"),
).json()
if (verification.witnesses.length === 0)
throw new Error("The saved export does not demonstrate the clearance bug")
const receiptFile = Bun.file(
resolve(projectDirectory, "outputs/publication.json"),
)
type PublicationReceipt = {
packageName: string
packageId: string
packageReleaseId: string
version: string
filesUploaded: string[]
previewVerified: boolean
}
let receipt: PublicationReceipt
if (await receiptFile.exists()) {
receipt = await receiptFile.json()
if (receipt.packageName !== packageName)
throw new Error(
"Publication receipt does not match this package and version",
)
if (receipt.version !== packageJson.version) {
const { package: existingPackage } = await registryRequest<{
package: { package_id: string }
}>("packages/get", { name: packageName })
if (existingPackage.package_id !== receipt.packageId)
throw new Error(
"Target package differs from the saved publication receipt",
)
await Bun.write(
resolve(projectDirectory, `outputs/publication.${receipt.version}.json`),
JSON.stringify(receipt, null, 2),
)
const { package_release } = await registryRequest<{
package_release: { package_release_id: string }
}>("package_releases/create", {
package_id: receipt.packageId,
version: packageJson.version,
is_latest: true,
ready_to_build: false,
})
receipt = {
...receipt,
packageReleaseId: package_release.package_release_id,
version: packageJson.version,
filesUploaded: [],
previewVerified: false,
}
await Bun.write(receiptFile, JSON.stringify(receipt, null, 2))
}
} else {
const existingPackage = await fetch(`${registryUrl}/packages/get`, {
method: "POST",
headers,
body: JSON.stringify({ name: packageName }),
signal: AbortSignal.timeout(30_000),
})
if (existingPackage.status !== 404)
throw new Error(
"Target already exists or cannot be checked; refusing to replace it",
)
const { package: createdPackage } = await registryRequest<{
package: { package_id: string }
}>("packages/create", {
name: packageName,
is_private: false,
is_unlisted: false,
})
const { package_release } = await registryRequest<{
package_release: { package_release_id: string }
}>("package_releases/create", {
package_id: createdPackage.package_id,
version: packageJson.version,
is_latest: true,
ready_to_build: false,
})
receipt = {
packageName,
packageId: createdPackage.package_id,
packageReleaseId: package_release.package_release_id,
version: packageJson.version,
filesUploaded: [],
previewVerified: false,
}
await Bun.write(receiptFile, JSON.stringify(receipt, null, 2))
}
const sourcePaths = [
"board.circuit.json",
"README.md",
"package.json",
"bun.lock",
"tsconfig.json",
"biome.json",
"tscircuit.config.json",
"assets.d.ts",
"reference.json",
"index.circuit.tsx",
"repro.circuit.tsx",
...new Bun.Glob("{components,imports,scripts,tests}/**/*").scanSync({
cwd: projectDirectory,
onlyFiles: true,
}),
...new Bun.Glob("outputs/repro/*").scanSync({
cwd: projectDirectory,
onlyFiles: true,
}),
]
const uploads = [
...sourcePaths.map((path) => ({ localPath: path, file_path: path })),
{
localPath: "board.circuit.json",
file_path: "dist/board.circuit.json",
},
{
localPath: "board.circuit.json",
file_path: "dist/board/circuit.json",
},
{
localPath: "outputs/repro/circuit.json",
file_path: "dist/repro.circuit/circuit.json",
},
{
localPath: "outputs/repro/circuit.json",
file_path: "dist/repro/circuit.json",
},
{ localPath: "outputs/repro/circuit.json", file_path: "dist/circuit.json" },
]
for (const { localPath, file_path } of uploads) {
if (receipt.filesUploaded.includes(file_path)) continue
const localFile = Bun.file(resolve(projectDirectory, localPath))
const archiveFile = {
file_path,
...(file_path.endsWith(".png")
? {
content_base64: Buffer.from(await localFile.arrayBuffer()).toString(
"base64",
),
content_mimetype: "image/png",
}
: {
content_text: await localFile.text(),
...(file_path.endsWith(".svg") && {
content_mimetype: "image/svg+xml",
}),
}),
}
await registryRequest("package_files/upload_archive", {
package_name_with_version: `${packageName}@${receipt.version}`,
archive_base64: gzipSync(JSON.stringify({ files: [archiveFile] }), {
level: 9,
}).toString("base64"),
})
receipt.filesUploaded.push(file_path)
await Bun.write(receiptFile, JSON.stringify(receipt, null, 2))
console.log(`Uploaded ${file_path}`)
}
await registryRequest("packages/update", {
package_id: receipt.packageId,
description: packageJson.description,
})
await registryRequest("package_releases/update", {
package_release_id: receipt.packageReleaseId,
ready_to_build: false,
})
const { preview_circuit_json_response: preview } = await registryRequest<{
preview_circuit_json_response: {
circuit_json_found: boolean
circuit_json?: unknown
}
}>("package_releases/get_preview_circuit_json", {
package_release_id: receipt.packageReleaseId,
})
receipt.previewVerified =
preview.circuit_json_found &&
isDeepStrictEqual(preview.circuit_json, nativeCircuit)
await Bun.write(receiptFile, JSON.stringify(receipt, null, 2))
if (!receipt.previewVerified)
throw new Error(
"Published preview is not identical to the verified native export",
)
console.log(
JSON.stringify({
url: `https://tscircuit.com/${packageName}#pcb`,
files: receipt.filesUploaded.length,
previewVerified: true,
}),
)