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-review-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 manifest=JSON.parse(fs.readFileSync("reports/review-fix-publish-manifest.json","utf8"))
const customBuild=Boolean(JSON.parse(fs.readFileSync(path.join(manifest.destination,"tscircuit.config.json"),"utf8")).buildCommand)
const previous=JSON.parse(fs.readFileSync("reports/pre-push-remote.json","utf8")).package
const releaseId="5903ad9d-2fa2-46dd-ba26-3f3eeca7dd01"
const root="https://registry-api.tscircuit.com/"
const sha=bytes=>crypto.createHash("sha256").update(bytes).digest("hex")
async function request(endpoint,{body,authenticated=false}={}){
  const token=authenticated?(process.env.TSCIRCUIT_TOKEN||JSON.parse(fs.readFileSync(path.join(os.homedir(),"Library/Preferences/tscircuit-nodejs/config.json"),"utf8")).sessionToken):null
  const response=await fetch(root+endpoint,{method:body?"POST":"GET",
    headers:{...(body?{"content-type":"application/json"}:{}),...(token?{authorization:`Bearer ${token}`}:{})},
    body:body?JSON.stringify(body):undefined,signal:AbortSignal.timeout(90000)})
  if(!response.ok)throw new Error(`${endpoint.split("?")[0]} HTTP ${response.status}`)
  return response.json()
}
const getRelease=async()=>(await request("package_releases/get",{body:{package_name_with_version:`${manifest.packageName}@${manifest.version}`}})).package_release
let release=await getRelease()
assert.equal(release.package_release_id,releaseId)
let pkg=(await request("packages/get",{body:{name:manifest.packageName}})).package
assert.ok([previous.latest_package_release_id,releaseId].includes(pkg.latest_package_release_id),"Do not supersede a concurrent unrelated update")
const listing=(await request("package_files/list?"+new URLSearchParams({package_release_id:releaseId}))).package_files
const files=new Map(listing.map(f=>[f.file_path,f]))
const report={checkedAt:new Date().toISOString(),packageName:manifest.packageName,version:manifest.version,releaseId,
  url:`https://tscircuit.com/${manifest.packageName}?version=${manifest.version}#3d`,
  fabricationReady:false,files:listing.length,readyToBuild:release.ready_to_build,
  buildMode:customBuild?"custom buildCommand":"registry circuit build",
  cloudBuildCompletedAt:release.user_code_job_completed_at,circuitBuildCompletedAt:release.circuit_json_build_completed_at,
  buildError:release.user_code_job_error??release.circuit_json_build_error,
  latestVersion:pkg.latest_version,latestVerified:pkg.latest_package_release_id===releaseId}
if(report.buildError)throw new Error(`Website build failed: ${String(report.buildError).slice(0,500)}`)
const readFile=async filename=>{
  const record=files.get(filename);assert.ok(record,`Uploaded file exists: ${filename}`)
  const f=(await request("package_files/get?"+new URLSearchParams({package_file_id:record.package_file_id}))).package_file
  return f.content_text!=null?Buffer.from(f.content_text):Buffer.from(f.content_base64??"","base64")
}
if(process.argv.includes("--verify-files")||process.argv.includes("--promote")){
  const pending=manifest.files.filter(f=>!f.file.startsWith("dist/")),checked=[]
  await Promise.all(Array.from({length:4},async()=>{
    while(pending.length){
      const f=pending.shift(),hash=sha(await readFile(f.file))
      assert.equal(hash,f.sha256,`Exact published source bytes: ${f.file}`)
      checked.push(f.file)
    }
  }))
  report.sourceFilesVerified=checked.length
}
if(process.argv.includes("--start-build")){
  assert.equal(report.sourceFilesVerified,manifest.files.filter(f=>!f.file.startsWith("dist/")).length)
  assert.ok(files.has("dist/index/circuit.json"))
  if(!release.ready_to_build){
    await request("package_releases/update",{body:{package_release_id:releaseId,ready_to_build:true},authenticated:true})
    release=await getRelease();report.readyToBuild=release.ready_to_build
  }
}
// Custom buildCommand releases finish through user_code_job; the separate
// registry circuit builder remains pending even on the prior successful release.
if(customBuild?release.user_code_job_completed_at:release.circuit_json_build_completed_at){
  const remote=await readFile("dist/index/circuit.json"),circuit=JSON.parse(remote)
  const local=JSON.parse(fs.readFileSync("dist/index/circuit.json","utf8"))
  assert.equal(sha(fs.readFileSync("dist/index/circuit.json")),manifest.circuitSha256)
  const types=new Set(["pcb_board","pcb_component","pcb_port","pcb_smtpad","pcb_plated_hole","pcb_hole",
    "pcb_trace","pcb_via","pcb_copper_pour","pcb_keepout","source_component","source_port","source_trace",
    "source_net","source_component_internal_connection"])
  const normalize=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=>types.has(e.type)).map(normalize).sort()
  assert.deepEqual(critical(circuit),critical(local),"Website copper, mechanics, BOM and electrical connections match the audited circuit")
  assert.equal(circuit.filter(e=>e.type.endsWith("_error")).length,0)
  assert.equal(circuit.filter(e=>e.type.endsWith("_warning")).length,150)
  report.websiteCircuitSha256=sha(remote)
  report.auditedCircuitSha256=manifest.circuitSha256
  report.websiteMatchesAuditedElectricalAndCopper=true
  report.nativeErrors=0;report.nativeWarnings=150
  fs.writeFileSync("reports/review-fix-website-circuit.json",remote)
  if(process.argv.includes("--promote")){
    assert.ok(report.sourceFilesVerified)
    if(pkg.latest_package_release_id!==releaseId)
      await request("package_releases/update",{body:{package_release_id:releaseId,is_latest:true},authenticated:true})
    pkg=(await request("packages/get",{body:{name:manifest.packageName}})).package
    assert.equal(pkg.latest_package_release_id,releaseId)
    const old=(await request("package_releases/get",{body:{package_name_with_version:`${manifest.packageName}@${previous.latest_version}`}})).package_release
    assert.equal(old.package_release_id,previous.latest_package_release_id)
    report.previousReleaseRetained=true;report.latestVerified=true;report.latestVersion=pkg.latest_version
  }
}
fs.writeFileSync("reports/review-fix-publication.json",JSON.stringify(report,null,2)+"\n")
console.log(JSON.stringify(report))
if(!report.websiteMatchesAuditedElectricalAndCopper)process.exitCode=2