shibosoftwaredev/f1c100s-linux-nema17-stepper-controller
A four-layer NEMA 17 motor-controller PCB combining an Allwinner F1C100S Linux computer, USB‑PD/buck power system, W5500 Ethernet, STM32 real-time motion control, DRV8825 stepper driver, protection/temperature/current telemetry, USB interfaces, and local LED/buzzer diagnostics.
- Version
- 0.4.56
- License
- unset
- Stars
- 0
scripts/verify-stencil-publication.mjs
import fs from "node:fs"
import os from "node:os"
import path from "node:path"
import crypto from "node:crypto"
import assert from "node:assert/strict"
const read=p=>JSON.parse(fs.readFileSync(p,"utf8"))
const sha=b=>crypto.createHash("sha256").update(b).digest("hex")
const manifest=read("reports/stencil-publish-manifest.json")
async function request(endpoint,{body,write=false}={}){
const token=write?(process.env.TSCIRCUIT_TOKEN??read(path.join(os.homedir(),"Library/Preferences/tscircuit-nodejs/config.json")).sessionToken):null
const r=await fetch(`https://registry-api.tscircuit.com/${endpoint}`,{method:body?"POST":"GET",
headers:{...(body?{"content-type":"application/json"}:{}),...(token?{authorization:`Bearer ${token}`}:{})},
body:body?JSON.stringify(body):undefined,signal:AbortSignal.timeout(45000)})
assert.ok(r.ok,`${endpoint.split("?")[0]}: HTTP ${r.status}`)
return r.json()
}
const release=(await request("package_releases/get",{body:{package_name_with_version:`${manifest.packageName}@${manifest.version}`}})).package_release
const pkg=(await request("packages/get",{body:{name:manifest.packageName}})).package
assert.ok([manifest.previous.releaseId,release.package_release_id].includes(pkg.latest_package_release_id),"no concurrent unrelated latest")
const files=(await request("package_files/list?"+new URLSearchParams({package_release_id:release.package_release_id}))).package_files
const byName=new Map(files.map(f=>[f.file_path,f]))
async function content(name){
const e=byName.get(name);assert.ok(e,`uploaded file ${name}`)
const f=(await request("package_files/get?"+new URLSearchParams({package_file_id:e.package_file_id}))).package_file
assert.ok(f.content_text!=null||f.content_base64!=null,`missing uploaded bytes ${name}: ${Object.keys(f).join(",")}`)
return f.content_text!=null?Buffer.from(f.content_text):Buffer.from(f.content_base64,"base64")
}
let sourceFilesVerified=null
if(process.argv.includes("--verify-files")||process.argv.includes("--promote")){
const pending=[...manifest.files],checked=[]
await Promise.all(Array.from({length:4},async()=>{while(pending.length){const f=pending.shift();assert.equal(sha(await content(f.file)),f.sha256,`published source ${f.file}`);checked.push(f.file)}}))
sourceFilesVerified=checked.length
}
const build=release.latest_package_build_id?(await request("package_builds/get?"+new URLSearchParams({package_build_id:release.latest_package_build_id}))).package_build:null
const error=build?.user_code_job_error??build?.circuit_json_build_error??build?.transpilation_error??release.user_code_job_error
const report={checkedAt:new Date().toISOString(),packageName:manifest.packageName,version:manifest.version,releaseId:release.package_release_id,
url:`https://tscircuit.com/${manifest.packageName}?version=${manifest.version}#3d`,buildId:release.latest_package_build_id,
sourceFilesVerified,readyToBuild:release.ready_to_build,buildStartedAt:build?.user_code_job_started_at??null,
buildCompletedAt:build?.user_code_job_completed_at??null,buildInProgress:build?.build_in_progress??false,buildError:error??null,
currentLatest:pkg.latest_version,latestVerified:pkg.latest_package_release_id===release.package_release_id,fabricationReady:false}
assert.ok(!error,`Website build error: ${String(error).slice(0,400)}`)
if(report.buildCompletedAt){
const bytes=await content("dist/index/circuit.json"),cloud=JSON.parse(bytes),local=read("dist/index/circuit.json")
assert.equal(sha(fs.readFileSync("dist/index/circuit.json")),manifest.circuitSha256)
const stable=value=>JSON.stringify(value,(_,v)=>typeof v==="number"?Math.round(v*1e8)/1e8:
v&&typeof v==="object"&&!Array.isArray(v)?Object.fromEntries(Object.entries(v).sort(([a],[b])=>a.localeCompare(b))):v)
const critical=c=>c.filter(e=>e.type!=="source_project_metadata"&&!e.type.endsWith("_warning")&&!e.type.endsWith("_error")).map(stable).sort()
assert.deepEqual(critical(cloud),critical(local),"website electrical/PCB/CAD/schematic/paste matches audited design")
assert.deepEqual(cloud.filter(e=>e.type.endsWith("_error")),[])
const warnings=cloud.filter(e=>e.type.endsWith("_warning"))
assert.equal(warnings.length,151)
const warningKey=e=>stable(Object.fromEntries(Object.entries(e).filter(([k])=>!k.endsWith("_warning_id"))))
assert.deepEqual(warnings.map(warningKey).sort(),local.filter(e=>e.type.endsWith("_warning")).map(warningKey).sort())
assert.equal(cloud.filter(e=>e.type==="pcb_solder_paste").length,674)
report.cloudCircuitSha256=sha(bytes);report.cloudMatchesAuditedBoard=true;report.nativeErrors=0;report.nativeWarnings=151
report.pasteApertures=674
fs.writeFileSync("reports/stencil-website-circuit.json",bytes)
if(process.argv.includes("--promote")){
assert.equal(sourceFilesVerified,manifest.files.length)
if(!report.latestVerified)await request("package_releases/update",{write:true,body:{package_release_id:release.package_release_id,is_latest:true}})
const current=(await request("packages/get",{body:{name:manifest.packageName}})).package
assert.equal(current.latest_package_release_id,release.package_release_id)
report.currentLatest=current.latest_version;report.latestVerified=true
}
}
fs.writeFileSync("reports/stencil-publication.json",JSON.stringify(report,null,2)+"\n")
console.log(JSON.stringify(report))
if(!report.cloudMatchesAuditedBoard)process.exitCode=2