[{"data":1,"prerenderedAt":876},["ShallowReactive",2],{"docs-\u002Fdocs\u002Fsdks\u002Fjavascript":3},{"id":4,"title":5,"body":6,"description":869,"extension":870,"meta":871,"navigation":121,"path":872,"seo":873,"stem":874,"__hash__":875},"content\u002Fdocs\u002Fsdks\u002Fjavascript.md","JavaScript SDK",{"type":7,"value":8,"toc":857},"minimark",[9,13,27,32,57,71,75,80,281,285,436,440,443,532,547,551,562,696,700,821,827,831,838,842,853],[10,11,5],"h1",{"id":12},"javascript-sdk",[14,15,16,20,21,26],"p",{},[17,18,19],"code",{},"conduyt-js"," is the pure-TypeScript SDK. It runs everywhere JavaScript runs — Node.js, Bun, Deno, browsers — and ships ESM-first with full TypeScript types. The protocol primitives (wire\u002FCOBS\u002FCRC8) are reimplemented in TypeScript; for a smaller browser bundle that uses the WASM-compiled Rust core instead, see the ",[22,23,25],"a",{"href":24},"\u002Fdocs\u002Fsdks\u002Fwasm","WASM SDK",".",[28,29,31],"h2",{"id":30},"install","Install",[33,34,39],"pre",{"className":35,"code":36,"language":37,"meta":38,"style":38},"language-bash shiki shiki-themes github-light github-dark","npm install conduyt-js\n","bash","",[17,40,41],{"__ignoreMap":38},[42,43,46,50,54],"span",{"class":44,"line":45},"line",1,[42,47,49],{"class":48},"sScJk","npm",[42,51,53],{"class":52},"sZZnC"," install",[42,55,56],{"class":52}," conduyt-js\n",[14,58,59,60,63,64,63,67,70],{},"Or with ",[17,61,62],{},"pnpm",", ",[17,65,66],{},"bun",[17,68,69],{},"yarn"," — same package.",[28,72,74],{"id":73},"quick-start","Quick start",[76,77,79],"h3",{"id":78},"nodejs-bun-usb-serial","Node.js \u002F Bun (USB-Serial)",[33,81,85],{"className":82,"code":83,"language":84,"meta":38,"style":38},"language-javascript shiki shiki-themes github-light github-dark","import { ConduytDevice } from 'conduyt-js'\nimport { SerialTransport } from 'conduyt-js\u002Ftransports\u002Fserial'\n\nconst transport = new SerialTransport({ path: '\u002Fdev\u002Fcu.usbmodem14101', baudRate: 115200 })\nconst device = await ConduytDevice.connect(transport)\n\nconsole.log('connected to', device.capabilities.firmwareName)\n\nawait device.pin(13).mode('output')\nawait device.pin(13).write(1)\n\nawait device.disconnect()\n","javascript",[17,86,87,103,116,123,157,179,184,202,207,238,263,268],{"__ignoreMap":38},[42,88,89,93,97,100],{"class":44,"line":45},[42,90,92],{"class":91},"szBVR","import",[42,94,96],{"class":95},"sVt8B"," { ConduytDevice } ",[42,98,99],{"class":91},"from",[42,101,102],{"class":52}," 'conduyt-js'\n",[42,104,106,108,111,113],{"class":44,"line":105},2,[42,107,92],{"class":91},[42,109,110],{"class":95}," { SerialTransport } ",[42,112,99],{"class":91},[42,114,115],{"class":52}," 'conduyt-js\u002Ftransports\u002Fserial'\n",[42,117,119],{"class":44,"line":118},3,[42,120,122],{"emptyLinePlaceholder":121},true,"\n",[42,124,126,129,133,136,139,142,145,148,151,154],{"class":44,"line":125},4,[42,127,128],{"class":91},"const",[42,130,132],{"class":131},"sj4cs"," transport",[42,134,135],{"class":91}," =",[42,137,138],{"class":91}," new",[42,140,141],{"class":48}," SerialTransport",[42,143,144],{"class":95},"({ path: ",[42,146,147],{"class":52},"'\u002Fdev\u002Fcu.usbmodem14101'",[42,149,150],{"class":95},", baudRate: ",[42,152,153],{"class":131},"115200",[42,155,156],{"class":95}," })\n",[42,158,160,162,165,167,170,173,176],{"class":44,"line":159},5,[42,161,128],{"class":91},[42,163,164],{"class":131}," device",[42,166,135],{"class":91},[42,168,169],{"class":91}," await",[42,171,172],{"class":95}," ConduytDevice.",[42,174,175],{"class":48},"connect",[42,177,178],{"class":95},"(transport)\n",[42,180,182],{"class":44,"line":181},6,[42,183,122],{"emptyLinePlaceholder":121},[42,185,187,190,193,196,199],{"class":44,"line":186},7,[42,188,189],{"class":95},"console.",[42,191,192],{"class":48},"log",[42,194,195],{"class":95},"(",[42,197,198],{"class":52},"'connected to'",[42,200,201],{"class":95},", device.capabilities.firmwareName)\n",[42,203,205],{"class":44,"line":204},8,[42,206,122],{"emptyLinePlaceholder":121},[42,208,210,213,216,219,221,224,227,230,232,235],{"class":44,"line":209},9,[42,211,212],{"class":91},"await",[42,214,215],{"class":95}," device.",[42,217,218],{"class":48},"pin",[42,220,195],{"class":95},[42,222,223],{"class":131},"13",[42,225,226],{"class":95},").",[42,228,229],{"class":48},"mode",[42,231,195],{"class":95},[42,233,234],{"class":52},"'output'",[42,236,237],{"class":95},")\n",[42,239,241,243,245,247,249,251,253,256,258,261],{"class":44,"line":240},10,[42,242,212],{"class":91},[42,244,215],{"class":95},[42,246,218],{"class":48},[42,248,195],{"class":95},[42,250,223],{"class":131},[42,252,226],{"class":95},[42,254,255],{"class":48},"write",[42,257,195],{"class":95},[42,259,260],{"class":131},"1",[42,262,237],{"class":95},[42,264,266],{"class":44,"line":265},11,[42,267,122],{"emptyLinePlaceholder":121},[42,269,271,273,275,278],{"class":44,"line":270},12,[42,272,212],{"class":91},[42,274,215],{"class":95},[42,276,277],{"class":48},"disconnect",[42,279,280],{"class":95},"()\n",[76,282,284],{"id":283},"browser-webserial","Browser (WebSerial)",[33,286,288],{"className":82,"code":287,"language":84,"meta":38,"style":38},"import { ConduytDevice } from 'conduyt-js'\nimport { WebSerialTransport } from 'conduyt-js\u002Ftransports\u002Fweb-serial'\n\n\u002F\u002F Inside a click \u002F keydown handler (WebSerial requires a user gesture).\n\u002F\u002F Don't call port.open() yourself — the transport opens the port internally\n\u002F\u002F using the baudRate option. Pre-opening throws \"port is already open\".\nconst port = await navigator.serial.requestPort()\nconst device = await ConduytDevice.connect(\n  new WebSerialTransport({ port, baudRate: 115200 })\n)\n\nawait device.pin(13).mode('output')\nawait device.pin(13).write(1)\n",[17,289,290,300,312,316,322,327,332,351,368,383,387,391,413],{"__ignoreMap":38},[42,291,292,294,296,298],{"class":44,"line":45},[42,293,92],{"class":91},[42,295,96],{"class":95},[42,297,99],{"class":91},[42,299,102],{"class":52},[42,301,302,304,307,309],{"class":44,"line":105},[42,303,92],{"class":91},[42,305,306],{"class":95}," { WebSerialTransport } ",[42,308,99],{"class":91},[42,310,311],{"class":52}," 'conduyt-js\u002Ftransports\u002Fweb-serial'\n",[42,313,314],{"class":44,"line":118},[42,315,122],{"emptyLinePlaceholder":121},[42,317,318],{"class":44,"line":125},[42,319,321],{"class":320},"sJ8bj","\u002F\u002F Inside a click \u002F keydown handler (WebSerial requires a user gesture).\n",[42,323,324],{"class":44,"line":159},[42,325,326],{"class":320},"\u002F\u002F Don't call port.open() yourself — the transport opens the port internally\n",[42,328,329],{"class":44,"line":181},[42,330,331],{"class":320},"\u002F\u002F using the baudRate option. Pre-opening throws \"port is already open\".\n",[42,333,334,336,339,341,343,346,349],{"class":44,"line":186},[42,335,128],{"class":91},[42,337,338],{"class":131}," port",[42,340,135],{"class":91},[42,342,169],{"class":91},[42,344,345],{"class":95}," navigator.serial.",[42,347,348],{"class":48},"requestPort",[42,350,280],{"class":95},[42,352,353,355,357,359,361,363,365],{"class":44,"line":204},[42,354,128],{"class":91},[42,356,164],{"class":131},[42,358,135],{"class":91},[42,360,169],{"class":91},[42,362,172],{"class":95},[42,364,175],{"class":48},[42,366,367],{"class":95},"(\n",[42,369,370,373,376,379,381],{"class":44,"line":209},[42,371,372],{"class":91},"  new",[42,374,375],{"class":48}," WebSerialTransport",[42,377,378],{"class":95},"({ port, baudRate: ",[42,380,153],{"class":131},[42,382,156],{"class":95},[42,384,385],{"class":44,"line":240},[42,386,237],{"class":95},[42,388,389],{"class":44,"line":265},[42,390,122],{"emptyLinePlaceholder":121},[42,392,393,395,397,399,401,403,405,407,409,411],{"class":44,"line":270},[42,394,212],{"class":91},[42,396,215],{"class":95},[42,398,218],{"class":48},[42,400,195],{"class":95},[42,402,223],{"class":131},[42,404,226],{"class":95},[42,406,229],{"class":48},[42,408,195],{"class":95},[42,410,234],{"class":52},[42,412,237],{"class":95},[42,414,416,418,420,422,424,426,428,430,432,434],{"class":44,"line":415},13,[42,417,212],{"class":91},[42,419,215],{"class":95},[42,421,218],{"class":48},[42,423,195],{"class":95},[42,425,223],{"class":131},[42,427,226],{"class":95},[42,429,255],{"class":48},[42,431,195],{"class":95},[42,433,260],{"class":131},[42,435,237],{"class":95},[28,437,439],{"id":438},"modules","Modules",[14,441,442],{},"The SDK ships typed wrappers for every CONDUYT firmware module. Import only what you need:",[33,444,446],{"className":82,"code":445,"language":84,"meta":38,"style":38},"import { ConduytServo }    from 'conduyt-js\u002Fmodules\u002Fservo'\nimport { ConduytNeoPixel } from 'conduyt-js\u002Fmodules\u002Fneopixel'\nimport { ConduytOLED }     from 'conduyt-js\u002Fmodules\u002Foled'\nimport { ConduytDHT }      from 'conduyt-js\u002Fmodules\u002Fdht'\nimport { ConduytEncoder }  from 'conduyt-js\u002Fmodules\u002Fencoder'\nimport { ConduytStepper }  from 'conduyt-js\u002Fmodules\u002Fstepper'\nimport { ConduytPID }      from 'conduyt-js\u002Fmodules\u002Fpid'\n",[17,447,448,460,472,484,496,508,520],{"__ignoreMap":38},[42,449,450,452,455,457],{"class":44,"line":45},[42,451,92],{"class":91},[42,453,454],{"class":95}," { ConduytServo }    ",[42,456,99],{"class":91},[42,458,459],{"class":52}," 'conduyt-js\u002Fmodules\u002Fservo'\n",[42,461,462,464,467,469],{"class":44,"line":105},[42,463,92],{"class":91},[42,465,466],{"class":95}," { ConduytNeoPixel } ",[42,468,99],{"class":91},[42,470,471],{"class":52}," 'conduyt-js\u002Fmodules\u002Fneopixel'\n",[42,473,474,476,479,481],{"class":44,"line":118},[42,475,92],{"class":91},[42,477,478],{"class":95}," { ConduytOLED }     ",[42,480,99],{"class":91},[42,482,483],{"class":52}," 'conduyt-js\u002Fmodules\u002Foled'\n",[42,485,486,488,491,493],{"class":44,"line":125},[42,487,92],{"class":91},[42,489,490],{"class":95}," { ConduytDHT }      ",[42,492,99],{"class":91},[42,494,495],{"class":52}," 'conduyt-js\u002Fmodules\u002Fdht'\n",[42,497,498,500,503,505],{"class":44,"line":159},[42,499,92],{"class":91},[42,501,502],{"class":95}," { ConduytEncoder }  ",[42,504,99],{"class":91},[42,506,507],{"class":52}," 'conduyt-js\u002Fmodules\u002Fencoder'\n",[42,509,510,512,515,517],{"class":44,"line":181},[42,511,92],{"class":91},[42,513,514],{"class":95}," { ConduytStepper }  ",[42,516,99],{"class":91},[42,518,519],{"class":52}," 'conduyt-js\u002Fmodules\u002Fstepper'\n",[42,521,522,524,527,529],{"class":44,"line":186},[42,523,92],{"class":91},[42,525,526],{"class":95}," { ConduytPID }      ",[42,528,99],{"class":91},[42,530,531],{"class":52}," 'conduyt-js\u002Fmodules\u002Fpid'\n",[14,533,534,535,538,539,542,543,546],{},"Each constructor takes a connected ",[17,536,537],{},"ConduytDevice"," and resolves the module ID by name from the ",[17,540,541],{},"HELLO_RESP",". See the per-module pages under ",[22,544,439],{"href":545},"\u002Fdocs\u002Fmodules\u002Fservo"," for command reference and examples.",[28,548,550],{"id":549},"datastreams","Datastreams",[14,552,553,554,557,558,561],{},"Datastreams are firmware-side named values (sensor readings, knobs, status) that auto-stream to the host. They appear in ",[17,555,556],{},"HELLO_RESP.datastreams",". Subscribe via the proxy returned by ",[17,559,560],{},"device.datastream(name)",":",[33,563,565],{"className":82,"code":564,"language":84,"meta":38,"style":38},"\u002F\u002F Read once\nconst raw = await device.datastream('temperature').read()\n\n\u002F\u002F Write a value (writable datastreams only)\nawait device.datastream('setpoint').write(22.5)\n\n\u002F\u002F Subscribe (async iterable)\nfor await (const value of device.datastream('temperature').subscribe()) {\n  console.log('temp:', value)\n}\n",[17,566,567,572,600,604,609,633,637,642,676,691],{"__ignoreMap":38},[42,568,569],{"class":44,"line":45},[42,570,571],{"class":320},"\u002F\u002F Read once\n",[42,573,574,576,579,581,583,585,588,590,593,595,598],{"class":44,"line":105},[42,575,128],{"class":91},[42,577,578],{"class":131}," raw",[42,580,135],{"class":91},[42,582,169],{"class":91},[42,584,215],{"class":95},[42,586,587],{"class":48},"datastream",[42,589,195],{"class":95},[42,591,592],{"class":52},"'temperature'",[42,594,226],{"class":95},[42,596,597],{"class":48},"read",[42,599,280],{"class":95},[42,601,602],{"class":44,"line":118},[42,603,122],{"emptyLinePlaceholder":121},[42,605,606],{"class":44,"line":125},[42,607,608],{"class":320},"\u002F\u002F Write a value (writable datastreams only)\n",[42,610,611,613,615,617,619,622,624,626,628,631],{"class":44,"line":159},[42,612,212],{"class":91},[42,614,215],{"class":95},[42,616,587],{"class":48},[42,618,195],{"class":95},[42,620,621],{"class":52},"'setpoint'",[42,623,226],{"class":95},[42,625,255],{"class":48},[42,627,195],{"class":95},[42,629,630],{"class":131},"22.5",[42,632,237],{"class":95},[42,634,635],{"class":44,"line":181},[42,636,122],{"emptyLinePlaceholder":121},[42,638,639],{"class":44,"line":186},[42,640,641],{"class":320},"\u002F\u002F Subscribe (async iterable)\n",[42,643,644,647,649,652,654,657,660,662,664,666,668,670,673],{"class":44,"line":204},[42,645,646],{"class":91},"for",[42,648,169],{"class":91},[42,650,651],{"class":95}," (",[42,653,128],{"class":91},[42,655,656],{"class":131}," value",[42,658,659],{"class":91}," of",[42,661,215],{"class":95},[42,663,587],{"class":48},[42,665,195],{"class":95},[42,667,592],{"class":52},[42,669,226],{"class":95},[42,671,672],{"class":48},"subscribe",[42,674,675],{"class":95},"()) {\n",[42,677,678,681,683,685,688],{"class":44,"line":209},[42,679,680],{"class":95},"  console.",[42,682,192],{"class":48},[42,684,195],{"class":95},[42,686,687],{"class":52},"'temp:'",[42,689,690],{"class":95},", value)\n",[42,692,693],{"class":44,"line":240},[42,694,695],{"class":95},"}\n",[28,697,699],{"id":698},"transports","Transports",[701,702,703,719],"table",{},[704,705,706],"thead",{},[707,708,709,713,716],"tr",{},[710,711,712],"th",{},"Transport",[710,714,715],{},"Module",[710,717,718],{},"Where it works",[720,721,722,740,753,766,782,795,808],"tbody",{},[707,723,724,728,733],{},[725,726,727],"td",{},"Node.js Serial",[725,729,730],{},[17,731,732],{},"conduyt-js\u002Ftransports\u002Fserial",[725,734,735,736,739],{},"Node, Bun, Electron (uses the ",[17,737,738],{},"serialport"," package)",[707,741,742,745,750],{},[725,743,744],{},"WebSerial",[725,746,747],{},[17,748,749],{},"conduyt-js\u002Ftransports\u002Fweb-serial",[725,751,752],{},"Chrome \u002F Edge \u002F Opera browsers",[707,754,755,758,763],{},[725,756,757],{},"BLE",[725,759,760],{},[17,761,762],{},"conduyt-js\u002Ftransports\u002Fble",[725,764,765],{},"Browsers with WebBluetooth (Chrome \u002F Edge desktop)",[707,767,768,771,776],{},[725,769,770],{},"MQTT",[725,772,773],{},[17,774,775],{},"conduyt-js\u002Ftransports\u002Fmqtt",[725,777,778,779,739],{},"Node and browsers (uses the ",[17,780,781],{},"mqtt",[707,783,784,787,792],{},[725,785,786],{},"WebSocket",[725,788,789],{},[17,790,791],{},"conduyt-js\u002Ftransports\u002Fwebsocket",[725,793,794],{},"Node and browsers",[707,796,797,800,805],{},[725,798,799],{},"CLASP",[725,801,802],{},[17,803,804],{},"conduyt-js\u002Ftransports\u002Fclasp",[725,806,807],{},"Browser CLASP tunnel",[707,809,810,813,818],{},[725,811,812],{},"Mock",[725,814,815],{},[17,816,817],{},"conduyt-js\u002Ftransports\u002Fmock",[725,819,820],{},"Tests. Captures sent bytes, lets you inject responses",[14,822,823,824,826],{},"For embedded targets that need a tiny binary instead of full TypeScript, use the ",[22,825,25],{"href":24}," directly.",[28,828,830],{"id":829},"typescript","TypeScript",[14,832,833,834,837],{},"Full types ship in the package. ",[17,835,836],{},"device.module('servo')"," returns a typed proxy so the IDE knows what commands the module accepts.",[28,839,841],{"id":840},"versioning","Versioning",[14,843,844,845,848,849,852],{},"The SDK follows the protocol version. ",[17,846,847],{},"1.x"," SDKs only talk to firmware running protocol version 2 (the current spec). The protocol version byte is exported as ",[17,850,851],{},"PROTOCOL_VERSION"," for runtime checks.",[854,855,856],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":38,"searchDepth":105,"depth":105,"links":858},[859,860,864,865,866,867,868],{"id":30,"depth":105,"text":31},{"id":73,"depth":105,"text":74,"children":861},[862,863],{"id":78,"depth":118,"text":79},{"id":283,"depth":118,"text":284},{"id":438,"depth":105,"text":439},{"id":549,"depth":105,"text":550},{"id":698,"depth":105,"text":699},{"id":829,"depth":105,"text":830},{"id":840,"depth":105,"text":841},"Pure-TS CONDUYT client for Node.js, Bun, Deno, and browsers — with WebSerial, BLE, and module wrappers.","md",{},"\u002Fdocs\u002Fsdks\u002Fjavascript",{"title":5,"description":869},"docs\u002Fsdks\u002Fjavascript","bRdPPWv_cFo3kRivtU0cdRKgYqRzYORKIiPFKBQXzhA",1777412315554]