app
Fusion - the Fusion 360 Bridge
Public Made by Adomby adom
Drive Autodesk Fusion 360 from the cloud via Adom Bridge: component libraries, IPC package generation, board layout, exports (STEP/Gerbers/BOM/CPL), fast APS cloud search, and parametric modeling.
← Commit history
v1.6.71: set User-Agent on service-step2glb calls (edge WAF 403s default Python-urllib UA)
4 files changed
+18−8
BRIDGE_VERSION+1−1@@ -1 +1 @@-1.6.70+1.6.71
adom-bridge-fusion-manifest.json+4−4@@ -1,10 +1,10 @@ { "manifest_version": 1, "name": "fusion360",- "version": "1.6.70",- "url": "https://wiki.adom.inc/download/adom/adom-desktop-fusion-bridge/1.6.70/adom-bridge-fusion-v1.6.70.zip",- "sha256": "242b2a59e11c052e50cc2148d631a05d1b51ff16c2c63e05952ccc262a854d80",- "size": 370757,+ "version": "1.6.71",+ "url": "https://wiki.adom.inc/download/adom/adom-desktop-fusion-bridge/1.6.71/adom-bridge-fusion-v1.6.71.zip",+ "sha256": "9682846f5acca6eece70813fd11615cfea597561cc0e71d9cbb32f3f445e575d",+ "size": 370945, "verbPrefixes": [ "fusion_" ],
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "fusion360", "displayName": "Autodesk Fusion 360",- "version": "1.6.70",+ "version": "1.6.71", "description": "Drive Autodesk Fusion 360 from the cloud: launch Fusion, electronics board layout, design rules, exports (STEP/IGES/STL/3MF/USDZ/OBJ/DXF/DWG/Gerbers/BOM/CPL), fast APS server-indexed cloud search plus browse/recent/file-info/versions, cloud file download/upload and folder creation, and in-app parametric modeling (fusion_run_modeling_script). Never-charge: APS calls are capped to the free tier.", "homepage": "https://wiki.adom.inc/adom/adom-desktop-fusion-bridge", "author": "Adom Inc.",
server.py+12−2@@ -3306,10 +3306,16 @@ def _service_glb_optimize(step_path: str, silk_top: str = None, silk_bottom: str except Exception: pass body, boundary = _multipart_body({}, files)+ # NOTE: a User-Agent is REQUIRED. The *.adom.cloud edge WAF 403s the default+ # "Python-urllib/x.y" UA (confirmed live 2026-07-14) while a browser/curl UA gets+ # 200. urllib sends the default on EVERY request (POST + both polls), so set it+ # on all three or the whole call fails with an opaque 403.+ _UA = "adom-fusion-bridge/%s" % BRIDGE_VERSION headers = { "Content-Type": "multipart/form-data; boundary=" + boundary, "X-Client": "fusion-bridge/adom", "X-Job-Name": job_name,+ "User-Agent": _UA, } url = "%s/convert?molecule=true&pin=%s" % (STEP2GLB_URL, urllib.parse.quote(pin)) try:@@ -3326,7 +3332,9 @@ def _service_glb_optimize(step_path: str, silk_top: str = None, silk_bottom: str stats, deadline = {}, _time.time() + poll_max_s while _time.time() < deadline: try:- with urllib.request.urlopen("%s/jobs/%s" % (STEP2GLB_URL, job_id), timeout=20) as r:+ preq = urllib.request.Request("%s/jobs/%s" % (STEP2GLB_URL, job_id),+ headers={"User-Agent": _UA})+ with urllib.request.urlopen(preq, timeout=20) as r: stats = json.loads(r.read().decode("utf-8", "replace")) except Exception: _time.sleep(5); continue@@ -3339,7 +3347,9 @@ def _service_glb_optimize(step_path: str, silk_top: str = None, silk_bottom: str else: return {"ok": False, "error": "service job did not finish within %ss" % poll_max_s, "jobId": job_id} try:- with urllib.request.urlopen("%s/jobs/%s/result" % (STEP2GLB_URL, job_id), timeout=60) as r:+ rreq = urllib.request.Request("%s/jobs/%s/result" % (STEP2GLB_URL, job_id),+ headers={"User-Agent": _UA})+ with urllib.request.urlopen(rreq, timeout=60) as r: glb = r.read() except Exception as e: return {"ok": False, "error": "could not download result GLB: %s" % e, "jobId": job_id}