@continuonai/rcan-ts 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2944,7 +2944,7 @@ var RobotURI = class _RobotURI {
2944
2944
  };
2945
2945
 
2946
2946
  // src/version.ts
2947
- var SPEC_VERSION = "1.5";
2947
+ var SPEC_VERSION = "1.6";
2948
2948
 
2949
2949
  // src/message.ts
2950
2950
  var RCANMessageError = class extends Error {
@@ -2974,6 +2974,12 @@ var RCANMessage = class _RCANMessage {
2974
2974
  presenceVerified;
2975
2975
  proximityMeters;
2976
2976
  readOnly;
2977
+ /** v1.6: GAP-14 level of assurance */
2978
+ loa;
2979
+ /** v1.6: GAP-17 transport encoding hint */
2980
+ transportEncoding;
2981
+ /** v1.6: GAP-18 multi-modal media chunks */
2982
+ mediaChunks;
2977
2983
  constructor(data) {
2978
2984
  if (!data.cmd || data.cmd.trim() === "") {
2979
2985
  throw new RCANMessageError("'cmd' is required");
@@ -2999,6 +3005,9 @@ var RCANMessage = class _RCANMessage {
2999
3005
  this.presenceVerified = data.presenceVerified;
3000
3006
  this.proximityMeters = data.proximityMeters;
3001
3007
  this.readOnly = data.readOnly;
3008
+ this.loa = data.loa;
3009
+ this.transportEncoding = data.transportEncoding;
3010
+ this.mediaChunks = data.mediaChunks;
3002
3011
  if (this.confidence !== void 0) {
3003
3012
  if (this.confidence < 0 || this.confidence > 1) {
3004
3013
  throw new RCANMessageError(
@@ -3037,6 +3046,9 @@ var RCANMessage = class _RCANMessage {
3037
3046
  if (this.presenceVerified !== void 0) obj.presenceVerified = this.presenceVerified;
3038
3047
  if (this.proximityMeters !== void 0) obj.proximityMeters = this.proximityMeters;
3039
3048
  if (this.readOnly !== void 0) obj.readOnly = this.readOnly;
3049
+ if (this.loa !== void 0) obj.loa = this.loa;
3050
+ if (this.transportEncoding !== void 0) obj.transportEncoding = this.transportEncoding;
3051
+ if (this.mediaChunks !== void 0) obj.mediaChunks = this.mediaChunks;
3040
3052
  return obj;
3041
3053
  }
3042
3054
  /** Serialize to JSON string */
@@ -3076,7 +3088,10 @@ var RCANMessage = class _RCANMessage {
3076
3088
  qos: obj.qos,
3077
3089
  presenceVerified: obj.presenceVerified,
3078
3090
  proximityMeters: obj.proximityMeters,
3079
- readOnly: obj.readOnly
3091
+ readOnly: obj.readOnly,
3092
+ loa: obj.loa,
3093
+ transportEncoding: obj.transportEncoding,
3094
+ mediaChunks: obj.mediaChunks
3080
3095
  });
3081
3096
  }
3082
3097
  };
package/dist/rcan.iife.js CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var RCAN=(()=>{var Re=Object.defineProperty;var ft=Object.getOwnPropertyDescriptor;var lt=Object.getOwnPropertyNames;var mt=Object.prototype.hasOwnProperty;var gt=(r=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(r,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):r)(function(r){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+r+'" is not supported')});var pt=(r,e)=>{for(var t in e)Re(r,t,{get:e[t],enumerable:!0})},ht=(r,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of lt(e))!mt.call(r,s)&&s!==t&&Re(r,s,{get:()=>e[s],enumerable:!(n=ft(e,s))||n.enumerable});return r};var yt=r=>ht(Re({},"__esModule",{value:!0}),r);var Pt={};pt(Pt,{AuditChain:()=>B,AuditError:()=>G,ClockDriftError:()=>L,CommitmentRecord:()=>P,ConfidenceGate:()=>J,DataCategory:()=>Ce,FaultCode:()=>Ae,GateError:()=>C,HiTLGate:()=>Y,KeyStore:()=>ue,MessageType:()=>T,NodeClient:()=>se,OfflineModeManager:()=>ge,QoSAckTimeoutError:()=>ie,QoSLevel:()=>xe,QoSManager:()=>ae,RCANAddressError:()=>W,RCANConfigAuthorizationError:()=>re,RCANDelegationChainError:()=>te,RCANError:()=>y,RCANGateError:()=>z,RCANMessage:()=>m,RCANMessageError:()=>v,RCANNodeError:()=>D,RCANNodeNotFoundError:()=>A,RCANNodeSyncError:()=>h,RCANNodeTrustError:()=>$,RCANRegistryError:()=>U,RCANReplayAttackError:()=>ee,RCANSignatureError:()=>X,RCANValidationError:()=>Q,RCANVersionIncompatibleError:()=>Z,RCAN_VERSION:()=>Dt,RegistryClient:()=>ne,ReplayCache:()=>de,RevocationCache:()=>K,RobotURI:()=>I,RobotURIError:()=>k,SAFETY_MESSAGE_TYPE:()=>we,SPEC_VERSION:()=>b,VERSION:()=>Ut,addDelegationHop:()=>Ie,assertClockSynced:()=>Be,checkClockSync:()=>Ee,checkRevocation:()=>Ze,fetchCanonicalSchema:()=>oe,isSafetyMessage:()=>Fe,makeCloudRelayMessage:()=>ke,makeConfigUpdate:()=>We,makeConsentDeny:()=>me,makeConsentGrant:()=>le,makeConsentRequest:()=>fe,makeEstopMessage:()=>Ke,makeEstopWithQoS:()=>Le,makeFaultReport:()=>ot,makeKeyRotationMessage:()=>ze,makeResumeMessage:()=>Ve,makeRevocationBroadcast:()=>et,makeStopMessage:()=>He,makeTrainingConsentDeny:()=>nt,makeTrainingConsentGrant:()=>rt,makeTrainingConsentRequest:()=>tt,makeTransparencyMessage:()=>Ye,validateConfig:()=>$e,validateConfigAgainstSchema:()=>qe,validateConfigUpdate:()=>Qe,validateConsentMessage:()=>Xe,validateDelegationChain:()=>Te,validateMessage:()=>Pe,validateNodeAgainstSchema:()=>je,validateReplay:()=>Ge,validateSafetyMessage:()=>Je,validateTrainingDataMessage:()=>st,validateURI:()=>De,validateVersionCompat:()=>Oe});var k=class extends Error{constructor(e){super(e),this.name="RobotURIError"}},I=class r{registry;manufacturer;model;version;deviceId;constructor(e){this.registry=e.registry,this.manufacturer=e.manufacturer,this.model=e.model,this.version=e.version,this.deviceId=e.deviceId}static parse(e){if(!e.startsWith("rcan://"))throw new k(`URI must start with 'rcan://' \u2014 got: ${e}`);let n=e.slice(7).split("/");if(n.length!==5)throw new k(`URI must have exactly 5 path segments (registry/manufacturer/model/version/device-id) \u2014 got ${n.length} in: ${e}`);let[s,o,i,c,d]=n;for(let[u,g]of[["registry",s],["manufacturer",o],["model",i],["version",c],["device-id",d]])if(!g||g.trim()==="")throw new k(`URI segment '${u}' must not be empty`);return new r({registry:s,manufacturer:o,model:i,version:c,deviceId:d})}static build(e){let t=e.registry??"registry.rcan.dev",{manufacturer:n,model:s,version:o,deviceId:i}=e;for(let[c,d]of[["manufacturer",n],["model",s],["version",o],["deviceId",i]])if(!d||d.trim()==="")throw new k(`'${c}' must not be empty`);return new r({registry:t,manufacturer:n,model:s,version:o,deviceId:i})}toString(){return`rcan://${this.registry}/${this.manufacturer}/${this.model}/${this.version}/${this.deviceId}`}get namespace(){return`${this.manufacturer}/${this.model}`}get registryUrl(){return`https://${this.registry}/registry/${this.manufacturer}/${this.model}/${this.version}/${this.deviceId}`}equals(e){return this.toString()===e.toString()}toJSON(){return{uri:this.toString(),registry:this.registry,manufacturer:this.manufacturer,model:this.model,version:this.version,deviceId:this.deviceId}}};var b="1.5";function Oe(r,e="1.5"){let t=o=>{let i=o.split("."),c=parseInt(i[0]??"0",10),d=parseInt(i[1]??"0",10);return[isNaN(c)?0:c,isNaN(d)?0:d]},[n]=t(r),[s]=t(e);return n===s}var T=(a=>(a[a.COMMAND=1]="COMMAND",a[a.RESPONSE=2]="RESPONSE",a[a.STATUS=3]="STATUS",a[a.HEARTBEAT=4]="HEARTBEAT",a[a.CONFIG=5]="CONFIG",a[a.SAFETY=6]="SAFETY",a[a.SENSOR_DATA=7]="SENSOR_DATA",a[a.AUDIT=8]="AUDIT",a[a.DISCOVER=9]="DISCOVER",a[a.TRAINING_DATA=10]="TRAINING_DATA",a[a.TRANSPARENCY=11]="TRANSPARENCY",a[a.FEDERATION_SYNC=12]="FEDERATION_SYNC",a[a.ALERT=13]="ALERT",a[a.TELEOP=14]="TELEOP",a[a.CHAT=15]="CHAT",a[a.ERROR=16]="ERROR",a[a.COMMAND_ACK=17]="COMMAND_ACK",a[a.COMMAND_COMMIT=18]="COMMAND_COMMIT",a[a.ROBOT_REVOCATION=19]="ROBOT_REVOCATION",a[a.CONSENT_REQUEST=20]="CONSENT_REQUEST",a[a.CONSENT_GRANT=21]="CONSENT_GRANT",a[a.CONSENT_DENY=22]="CONSENT_DENY",a[a.FLEET_COMMAND=23]="FLEET_COMMAND",a[a.SUBSCRIBE=24]="SUBSCRIBE",a[a.UNSUBSCRIBE=25]="UNSUBSCRIBE",a[a.FAULT_REPORT=26]="FAULT_REPORT",a[a.COMMAND_NACK=27]="COMMAND_NACK",a))(T||{}),v=class extends Error{constructor(e){super(e),this.name="RCANMessageError"}},m=class r{rcan;rcanVersion;cmd;target;params;confidence;modelIdentity;signature;timestamp;senderType;cloudProvider;keyId;delegationChain;groupId;qos;presenceVerified;proximityMeters;readOnly;constructor(e){if(!e.cmd||e.cmd.trim()==="")throw new v("'cmd' is required");if(!e.target)throw new v("'target' is required");if(this.rcan=e.rcan??"1.5",this.rcanVersion=e.rcanVersion??"1.5",this.cmd=e.cmd,this.target=e.target instanceof I?e.target.toString():String(e.target),this.params=e.params??{},this.confidence=e.confidence,this.modelIdentity=e.modelIdentity??e.model_identity,this.signature=e.signature,this.timestamp=e.timestamp??new Date().toISOString(),this.senderType=e.senderType,this.cloudProvider=e.cloudProvider,this.keyId=e.keyId,this.delegationChain=e.delegationChain,this.groupId=e.groupId,this.qos=e.qos,this.presenceVerified=e.presenceVerified,this.proximityMeters=e.proximityMeters,this.readOnly=e.readOnly,this.confidence!==void 0&&(this.confidence<0||this.confidence>1))throw new v(`confidence must be in [0.0, 1.0] \u2014 got ${this.confidence}`)}get isSigned(){return this.signature!==void 0&&this.signature.sig!==""}get isAiDriven(){return this.confidence!==void 0}toJSON(){let e={rcan:this.rcan,rcanVersion:this.rcanVersion,cmd:this.cmd,target:this.target,timestamp:this.timestamp};return Object.keys(this.params).length>0&&(e.params=this.params),this.confidence!==void 0&&(e.confidence=this.confidence),this.modelIdentity&&(e.model_identity=this.modelIdentity),this.signature&&(e.signature=this.signature),this.senderType!==void 0&&(e.senderType=this.senderType),this.cloudProvider!==void 0&&(e.cloudProvider=this.cloudProvider),this.keyId!==void 0&&(e.keyId=this.keyId),this.delegationChain!==void 0&&(e.delegationChain=this.delegationChain),this.groupId!==void 0&&(e.groupId=this.groupId),this.qos!==void 0&&(e.qos=this.qos),this.presenceVerified!==void 0&&(e.presenceVerified=this.presenceVerified),this.proximityMeters!==void 0&&(e.proximityMeters=this.proximityMeters),this.readOnly!==void 0&&(e.readOnly=this.readOnly),e}toJSONString(e){return JSON.stringify(this.toJSON(),null,e)}static fromJSON(e){let t;if(typeof e=="string")try{t=JSON.parse(e)}catch{throw new v("Invalid JSON string")}else t=e;if(!t.cmd)throw new v("Missing required field: 'cmd'");if(!t.target)throw new v("Missing required field: 'target'");if(!t.rcan)throw new v("Missing required field: 'rcan'");return new r({rcan:t.rcan,rcanVersion:t.rcanVersion,cmd:t.cmd,target:t.target,params:t.params??{},confidence:t.confidence,modelIdentity:t.model_identity??t.modelIdentity,signature:t.signature,timestamp:t.timestamp,senderType:t.senderType,cloudProvider:t.cloudProvider,keyId:t.keyId,delegationChain:t.delegationChain,groupId:t.groupId,qos:t.qos,presenceVerified:t.presenceVerified,proximityMeters:t.proximityMeters,readOnly:t.readOnly})}};function ke(r,e){let t=r.toJSON();return t.senderType="cloud_function",t.cloudProvider=e,new m(t)}function Ie(r,e){let t=r.delegationChain?[...r.delegationChain,e]:[e],n=r.toJSON();return n.delegationChain=t,new m(n)}function Te(r){if(r.length>4)return{valid:!1,reason:"DELEGATION_CHAIN_EXCEEDED: max depth is 4 hops"};for(let e=0;e<r.length;e++){let t=r[e];if(!t)return{valid:!1,reason:`hop ${e} is undefined`};if(!t.issuerRuri)return{valid:!1,reason:`hop ${e}: missing issuerRuri`};if(!t.humanSubject)return{valid:!1,reason:`hop ${e}: missing humanSubject`};if(!t.timestamp)return{valid:!1,reason:`hop ${e}: missing timestamp`};if(!t.scope)return{valid:!1,reason:`hop ${e}: missing scope`};if(!t.signature)return{valid:!1,reason:`hop ${e}: missing signature`}}return{valid:!0,reason:"ok"}}function F(){if(typeof globalThis.crypto<"u"&&typeof globalThis.crypto.randomUUID=="function")return globalThis.crypto.randomUUID();try{let{randomUUID:r}=gt("crypto");return r()}catch{return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,r=>{let e=Math.random()*16|0;return(r==="x"?e:e&3|8).toString(16)})}}function Se(r,e){return typeof process<"u",_t(r,e)}function _e(r){let e=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298],t=1779033703,n=3144134277,s=1013904242,o=2773480762,i=1359893119,c=2600822924,d=528734635,u=1541459225,it=r.length*8,E=[...r];for(E.push(128);E.length%64!==56;)E.push(0);for(let S=7;S>=0;S--)E.push(it/Math.pow(2,S*8)&255);for(let S=0;S<E.length;S+=64){let R=[];for(let f=0;f<16;f++)R[f]=E[S+f*4]<<24|E[S+f*4+1]<<16|E[S+f*4+2]<<8|E[S+f*4+3];for(let f=16;f<64;f++){let ye=x(R[f-15],7)^x(R[f-15],18)^R[f-15]>>>3,a=x(R[f-2],17)^x(R[f-2],19)^R[f-2]>>>10;R[f]=R[f-16]+ye+R[f-7]+a>>>0}let[N,q,j,pe,O,H,V,he]=[t,n,s,o,i,c,d,u];for(let f=0;f<64;f++){let ye=x(O,6)^x(O,11)^x(O,25),a=O&H^~O&V,Ne=he+ye+a+e[f]+R[f]>>>0,ct=x(N,2)^x(N,13)^x(N,22),dt=N&q^N&j^q&j,ut=ct+dt>>>0;[he,V,H,O,pe,j,q,N]=[V,H,O,pe+Ne>>>0,j,q,N,Ne+ut>>>0]}t=t+N>>>0,n=n+q>>>0,s=s+j>>>0,o=o+pe>>>0,i=i+O>>>0,c=c+H>>>0,d=d+V>>>0,u=u+he>>>0}let p=new Uint8Array(32),at=new DataView(p.buffer);return[t,n,s,o,i,c,d,u].forEach((S,R)=>at.setUint32(R*4,S)),p}function x(r,e){return r>>>e|r<<32-e}function Me(r){if(typeof TextEncoder<"u")return new TextEncoder().encode(r);let e=new Uint8Array(r.length);for(let t=0;t<r.length;t++)e[t]=r.charCodeAt(t)&255;return e}function Rt(r){return Array.from(r).map(e=>e.toString(16).padStart(2,"0")).join("")}function _t(r,e){let n=Me(r);n.length>64&&(n=_e(n));let s=new Uint8Array(64),o=new Uint8Array(64);for(let g=0;g<64;g++)s[g]=(n[g]??0)^54,o[g]=(n[g]??0)^92;let i=Me(e),c=new Uint8Array(64+i.length);c.set(s),c.set(i,64);let d=_e(c),u=new Uint8Array(96);return u.set(o),u.set(d,64),Rt(_e(u))}var C=class extends Error{constructor(e){super(e),this.name="GateError"}},J=class{threshold;constructor(e=.8){if(e<0||e>1)throw new C(`threshold must be in [0.0, 1.0] \u2014 got ${e}`);this.threshold=e}allows(e){return e>=this.threshold}margin(e){return e-this.threshold}assert(e,t){if(!this.allows(e)){let n=t?` for action '${t}'`:"";throw new C(`Confidence ${e}${n} is below threshold ${this.threshold}`)}}},Y=class{_pending=new Map;request(e,t={}){let n=F();return this._pending.set(n,{token:n,action:e,context:t,createdAt:new Date().toISOString(),status:"pending"}),n}approve(e){let t=this._pending.get(e);if(!t)throw new C(`Unknown token: ${e}`);t.status="approved"}deny(e,t){let n=this._pending.get(e);if(!n)throw new C(`Unknown token: ${e}`);n.status="denied",t&&(n.reason=t)}check(e){let t=this._pending.get(e);if(!t)throw new C(`Unknown token: ${e}`);return t.status}get pendingApprovals(){return Array.from(this._pending.values()).filter(e=>e.status==="pending")}getApproval(e){return this._pending.get(e)}clearResolved(){for(let[e,t]of this._pending.entries())t.status!=="pending"&&this._pending.delete(e)}};var G=class extends Error{constructor(e){super(e),this.name="AuditError"}};function St(r,e,t,n,s){let o=JSON.stringify({recordId:r,action:e,robotUri:t,timestamp:n,params:s},Object.keys({recordId:r,action:e,robotUri:t,timestamp:n,params:s}).sort());return Se("rcan-content-hash",o)}function Ue(r,e){let{hmac:t,...n}=e,s=JSON.stringify(n,Object.keys(n).sort());return Se(r,s)}var P=class r{recordId;action;robotUri;confidence;modelIdentity;params;safetyApproved;timestamp;contentHash;previousHash;hmac;constructor(e){this.recordId=e.recordId,this.action=e.action,this.robotUri=e.robotUri,this.confidence=e.confidence,this.modelIdentity=e.modelIdentity,this.params=e.params,this.safetyApproved=e.safetyApproved,this.timestamp=e.timestamp,this.contentHash=e.contentHash,this.previousHash=e.previousHash,this.hmac=e.hmac}static create(e,t,n=null){let s=F(),o=new Date().toISOString(),i=e.params??{},c=e.robotUri??"",d=St(s,e.action,c,o,i),u={recordId:s,action:e.action,robotUri:c,confidence:e.confidence,modelIdentity:e.modelIdentity,params:i,safetyApproved:e.safetyApproved??!0,timestamp:o,contentHash:d,previousHash:n,hmac:""};return u.hmac=Ue(t,u),new r(u)}verify(e){return Ue(e,this.toJSON())===this.hmac}toJSON(){return{recordId:this.recordId,action:this.action,robotUri:this.robotUri,confidence:this.confidence,modelIdentity:this.modelIdentity,params:this.params,safetyApproved:this.safetyApproved,timestamp:this.timestamp,contentHash:this.contentHash,previousHash:this.previousHash,hmac:this.hmac}}static fromJSON(e){return new r(e)}},B=class r{_records=[];_secret;constructor(e){this._secret=e}get records(){return this._records}append(e){let n=this._records[this._records.length-1]?.contentHash??null,s=P.create(e,this._secret,n);return this._records.push(s),s}verifyAll(){let e=[],t=null;for(let n of this._records)n.verify(this._secret)||e.push(`HMAC invalid for record ${n.recordId.slice(0,8)}`),t!==null&&n.previousHash!==t&&e.push(`Chain broken at ${n.recordId.slice(0,8)}: expected prev=${t.slice(0,12)}`),t=n.contentHash;return{valid:e.length===0,count:this._records.length,errors:e}}toJSONL(){return this._records.map(e=>JSON.stringify(e.toJSON())).join(`
1
+ "use strict";var RCAN=(()=>{var we=Object.defineProperty;var Gt=Object.getOwnPropertyDescriptor;var Wt=Object.getOwnPropertyNames;var zt=Object.prototype.hasOwnProperty;var ze=(n=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(n,{get:(e,t)=>(typeof require<"u"?require:e)[t]}):n)(function(n){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+n+'" is not supported')});var Qt=(n,e)=>{for(var t in e)we(n,t,{get:e[t],enumerable:!0})},Xt=(n,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Wt(e))!zt.call(n,s)&&s!==t&&we(n,s,{get:()=>e[s],enumerable:!(r=Gt(e,s))||r.enumerable});return n};var Zt=n=>Xt(we({},"__esModule",{value:!0}),n);var vn={};Qt(vn,{AuditChain:()=>ee,AuditError:()=>Z,ClockDriftError:()=>B,CommitmentRecord:()=>$,ConfidenceGate:()=>Q,DEFAULT_LOA_POLICY:()=>Le,DataCategory:()=>Pe,FaultCode:()=>De,FederationSyncType:()=>je,GateError:()=>O,HiTLGate:()=>X,KeyStore:()=>he,LevelOfAssurance:()=>Ae,MediaEncoding:()=>Ve,MessageType:()=>C,NodeClient:()=>ue,OfflineModeManager:()=>_e,PRODUCTION_LOA_POLICY:()=>Ot,QoSAckTimeoutError:()=>le,QoSLevel:()=>Ie,QoSManager:()=>ge,RCANAddressError:()=>te,RCANConfigAuthorizationError:()=>ce,RCANDelegationChainError:()=>ae,RCANError:()=>R,RCANGateError:()=>re,RCANMessage:()=>l,RCANMessageError:()=>v,RCANNodeError:()=>L,RCANNodeNotFoundError:()=>k,RCANNodeSyncError:()=>y,RCANNodeTrustError:()=>j,RCANRegistryError:()=>D,RCANReplayAttackError:()=>ie,RCANSignatureError:()=>se,RCANValidationError:()=>ne,RCANVersionIncompatibleError:()=>oe,RCAN_VERSION:()=>bn,RegistryClient:()=>de,RegistryTier:()=>$e,ReplayCache:()=>pe,RevocationCache:()=>K,RobotURI:()=>U,RobotURIError:()=>M,SAFETY_MESSAGE_TYPE:()=>Me,SDK_VERSION:()=>Qe,SPEC_VERSION:()=>b,TransportEncoding:()=>He,TransportError:()=>x,TrustAnchorCache:()=>ve,VERSION:()=>An,addDelegationHop:()=>et,addMediaInline:()=>Ge,addMediaRef:()=>Ft,assertClockSynced:()=>yt,checkClockSync:()=>Ue,checkRevocation:()=>bt,decodeBleFrames:()=>$t,decodeCompact:()=>Ke,decodeMinimal:()=>Dt,encodeBleFrames:()=>Lt,encodeCompact:()=>Be,encodeMinimal:()=>Pt,extractLoaFromJwt:()=>be,fetchCanonicalSchema:()=>fe,isSafetyMessage:()=>gt,makeCloudRelayMessage:()=>Ze,makeConfigUpdate:()=>Rt,makeConsentDeny:()=>Se,makeConsentGrant:()=>Re,makeConsentRequest:()=>ye,makeEstopMessage:()=>ut,makeEstopWithQoS:()=>dt,makeFaultReport:()=>Nt,makeFederationSync:()=>Tt,makeKeyRotationMessage:()=>_t,makeResumeMessage:()=>lt,makeRevocationBroadcast:()=>vt,makeStopMessage:()=>ft,makeStreamChunk:()=>Kt,makeTrainingConsentDeny:()=>Et,makeTrainingConsentGrant:()=>Ct,makeTrainingConsentRequest:()=>xt,makeTrainingDataMessage:()=>Bt,makeTransparencyMessage:()=>pt,selectTransport:()=>jt,validateConfig:()=>it,validateConfigAgainstSchema:()=>at,validateConfigUpdate:()=>St,validateConsentMessage:()=>At,validateCrossRegistryCommand:()=>It,validateDelegationChain:()=>tt,validateLoaForScope:()=>kt,validateMediaChunks:()=>Ht,validateMessage:()=>ot,validateNodeAgainstSchema:()=>ct,validateReplay:()=>ht,validateSafetyMessage:()=>mt,validateTrainingDataMessage:()=>wt,validateURI:()=>st,validateVersionCompat:()=>Xe});var M=class extends Error{constructor(e){super(e),this.name="RobotURIError"}},U=class n{registry;manufacturer;model;version;deviceId;constructor(e){this.registry=e.registry,this.manufacturer=e.manufacturer,this.model=e.model,this.version=e.version,this.deviceId=e.deviceId}static parse(e){if(!e.startsWith("rcan://"))throw new M(`URI must start with 'rcan://' \u2014 got: ${e}`);let r=e.slice(7).split("/");if(r.length!==5)throw new M(`URI must have exactly 5 path segments (registry/manufacturer/model/version/device-id) \u2014 got ${r.length} in: ${e}`);let[s,o,i,a,c]=r;for(let[u,f]of[["registry",s],["manufacturer",o],["model",i],["version",a],["device-id",c]])if(!f||f.trim()==="")throw new M(`URI segment '${u}' must not be empty`);return new n({registry:s,manufacturer:o,model:i,version:a,deviceId:c})}static build(e){let t=e.registry??"registry.rcan.dev",{manufacturer:r,model:s,version:o,deviceId:i}=e;for(let[a,c]of[["manufacturer",r],["model",s],["version",o],["deviceId",i]])if(!c||c.trim()==="")throw new M(`'${a}' must not be empty`);return new n({registry:t,manufacturer:r,model:s,version:o,deviceId:i})}toString(){return`rcan://${this.registry}/${this.manufacturer}/${this.model}/${this.version}/${this.deviceId}`}get namespace(){return`${this.manufacturer}/${this.model}`}get registryUrl(){return`https://${this.registry}/registry/${this.manufacturer}/${this.model}/${this.version}/${this.deviceId}`}equals(e){return this.toString()===e.toString()}toJSON(){return{uri:this.toString(),registry:this.registry,manufacturer:this.manufacturer,model:this.model,version:this.version,deviceId:this.deviceId}}};var b="1.6",Qe="0.6.0";function Xe(n,e="1.6"){let t=o=>{let i=o.split("."),a=parseInt(i[0]??"0",10),c=parseInt(i[1]??"0",10);return[isNaN(a)?0:a,isNaN(c)?0:c]},[r]=t(n),[s]=t(e);return r===s}var C=(d=>(d[d.COMMAND=1]="COMMAND",d[d.RESPONSE=2]="RESPONSE",d[d.STATUS=3]="STATUS",d[d.HEARTBEAT=4]="HEARTBEAT",d[d.CONFIG=5]="CONFIG",d[d.SAFETY=6]="SAFETY",d[d.SENSOR_DATA=7]="SENSOR_DATA",d[d.AUDIT=8]="AUDIT",d[d.DISCOVER=9]="DISCOVER",d[d.TRAINING_DATA=10]="TRAINING_DATA",d[d.TRANSPARENCY=11]="TRANSPARENCY",d[d.FEDERATION_SYNC=12]="FEDERATION_SYNC",d[d.ALERT=13]="ALERT",d[d.TELEOP=14]="TELEOP",d[d.CHAT=15]="CHAT",d[d.ERROR=16]="ERROR",d[d.COMMAND_ACK=17]="COMMAND_ACK",d[d.COMMAND_COMMIT=18]="COMMAND_COMMIT",d[d.ROBOT_REVOCATION=19]="ROBOT_REVOCATION",d[d.CONSENT_REQUEST=20]="CONSENT_REQUEST",d[d.CONSENT_GRANT=21]="CONSENT_GRANT",d[d.CONSENT_DENY=22]="CONSENT_DENY",d[d.FLEET_COMMAND=23]="FLEET_COMMAND",d[d.SUBSCRIBE=24]="SUBSCRIBE",d[d.UNSUBSCRIBE=25]="UNSUBSCRIBE",d[d.FAULT_REPORT=26]="FAULT_REPORT",d[d.COMMAND_NACK=27]="COMMAND_NACK",d))(C||{}),v=class extends Error{constructor(e){super(e),this.name="RCANMessageError"}},l=class n{rcan;rcanVersion;cmd;target;params;confidence;modelIdentity;signature;timestamp;senderType;cloudProvider;keyId;delegationChain;groupId;qos;presenceVerified;proximityMeters;readOnly;loa;transportEncoding;mediaChunks;constructor(e){if(!e.cmd||e.cmd.trim()==="")throw new v("'cmd' is required");if(!e.target)throw new v("'target' is required");if(this.rcan=e.rcan??"1.6",this.rcanVersion=e.rcanVersion??"1.6",this.cmd=e.cmd,this.target=e.target instanceof U?e.target.toString():String(e.target),this.params=e.params??{},this.confidence=e.confidence,this.modelIdentity=e.modelIdentity??e.model_identity,this.signature=e.signature,this.timestamp=e.timestamp??new Date().toISOString(),this.senderType=e.senderType,this.cloudProvider=e.cloudProvider,this.keyId=e.keyId,this.delegationChain=e.delegationChain,this.groupId=e.groupId,this.qos=e.qos,this.presenceVerified=e.presenceVerified,this.proximityMeters=e.proximityMeters,this.readOnly=e.readOnly,this.loa=e.loa,this.transportEncoding=e.transportEncoding,this.mediaChunks=e.mediaChunks,this.confidence!==void 0&&(this.confidence<0||this.confidence>1))throw new v(`confidence must be in [0.0, 1.0] \u2014 got ${this.confidence}`)}get isSigned(){return this.signature!==void 0&&this.signature.sig!==""}get isAiDriven(){return this.confidence!==void 0}toJSON(){let e={rcan:this.rcan,rcanVersion:this.rcanVersion,cmd:this.cmd,target:this.target,timestamp:this.timestamp};return Object.keys(this.params).length>0&&(e.params=this.params),this.confidence!==void 0&&(e.confidence=this.confidence),this.modelIdentity&&(e.model_identity=this.modelIdentity),this.signature&&(e.signature=this.signature),this.senderType!==void 0&&(e.senderType=this.senderType),this.cloudProvider!==void 0&&(e.cloudProvider=this.cloudProvider),this.keyId!==void 0&&(e.keyId=this.keyId),this.delegationChain!==void 0&&(e.delegationChain=this.delegationChain),this.groupId!==void 0&&(e.groupId=this.groupId),this.qos!==void 0&&(e.qos=this.qos),this.presenceVerified!==void 0&&(e.presenceVerified=this.presenceVerified),this.proximityMeters!==void 0&&(e.proximityMeters=this.proximityMeters),this.readOnly!==void 0&&(e.readOnly=this.readOnly),this.loa!==void 0&&(e.loa=this.loa),this.transportEncoding!==void 0&&(e.transportEncoding=this.transportEncoding),this.mediaChunks!==void 0&&(e.mediaChunks=this.mediaChunks),e}toJSONString(e){return JSON.stringify(this.toJSON(),null,e)}static fromJSON(e){let t;if(typeof e=="string")try{t=JSON.parse(e)}catch{throw new v("Invalid JSON string")}else t=e;if(!t.cmd)throw new v("Missing required field: 'cmd'");if(!t.target)throw new v("Missing required field: 'target'");if(!t.rcan)throw new v("Missing required field: 'rcan'");return new n({rcan:t.rcan,rcanVersion:t.rcanVersion,cmd:t.cmd,target:t.target,params:t.params??{},confidence:t.confidence,modelIdentity:t.model_identity??t.modelIdentity,signature:t.signature,timestamp:t.timestamp,senderType:t.senderType,cloudProvider:t.cloudProvider,keyId:t.keyId,delegationChain:t.delegationChain,groupId:t.groupId,qos:t.qos,presenceVerified:t.presenceVerified,proximityMeters:t.proximityMeters,readOnly:t.readOnly,loa:t.loa,transportEncoding:t.transportEncoding,mediaChunks:t.mediaChunks})}};function Ze(n,e){let t=n.toJSON();return t.senderType="cloud_function",t.cloudProvider=e,new l(t)}function et(n,e){let t=n.delegationChain?[...n.delegationChain,e]:[e],r=n.toJSON();return r.delegationChain=t,new l(r)}function tt(n){if(n.length>4)return{valid:!1,reason:"DELEGATION_CHAIN_EXCEEDED: max depth is 4 hops"};for(let e=0;e<n.length;e++){let t=n[e];if(!t)return{valid:!1,reason:`hop ${e} is undefined`};if(!t.issuerRuri)return{valid:!1,reason:`hop ${e}: missing issuerRuri`};if(!t.humanSubject)return{valid:!1,reason:`hop ${e}: missing humanSubject`};if(!t.timestamp)return{valid:!1,reason:`hop ${e}: missing timestamp`};if(!t.scope)return{valid:!1,reason:`hop ${e}: missing scope`};if(!t.signature)return{valid:!1,reason:`hop ${e}: missing signature`}}return{valid:!0,reason:"ok"}}function z(){if(typeof globalThis.crypto<"u"&&typeof globalThis.crypto.randomUUID=="function")return globalThis.crypto.randomUUID();try{let{randomUUID:n}=ze("crypto");return n()}catch{return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,n=>{let e=Math.random()*16|0;return(n==="x"?e:e&3|8).toString(16)})}}function Oe(n,e){return typeof process<"u",tn(n,e)}function Ne(n){let e=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298],t=1779033703,r=3144134277,s=1013904242,o=2773480762,i=1359893119,a=2600822924,c=528734635,u=1541459225,q=n.length*8,A=[...n];for(A.push(128);A.length%64!==56;)A.push(0);for(let h=7;h>=0;h--)A.push(q/Math.pow(2,h*8)&255);for(let h=0;h<A.length;h+=64){let S=[];for(let m=0;m<16;m++)S[m]=A[h+m*4]<<24|A[h+m*4+1]<<16|A[h+m*4+2]<<8|A[h+m*4+3];for(let m=16;m<64;m++){let Ee=E(S[m-15],7)^E(S[m-15],18)^S[m-15]>>>3,d=E(S[m-2],17)^E(S[m-2],19)^S[m-2]>>>10;S[m]=S[m-16]+Ee+S[m-7]+d>>>0}let[T,F,H,xe,I,G,W,Ce]=[t,r,s,o,i,a,c,u];for(let m=0;m<64;m++){let Ee=E(I,6)^E(I,11)^E(I,25),d=I&G^~I&W,We=Ce+Ee+d+e[m]+S[m]>>>0,Vt=E(T,2)^E(T,13)^E(T,22),Yt=T&F^T&H^F&H,Jt=Vt+Yt>>>0;[Ce,W,G,I,xe,H,F,T]=[W,G,I,xe+We>>>0,H,F,T,We+Jt>>>0]}t=t+T>>>0,r=r+F>>>0,s=s+H>>>0,o=o+xe>>>0,i=i+I>>>0,a=a+G>>>0,c=c+W>>>0,u=u+Ce>>>0}let p=new Uint8Array(32),N=new DataView(p.buffer);return[t,r,s,o,i,a,c,u].forEach((h,S)=>N.setUint32(S*4,h)),p}function E(n,e){return n>>>e|n<<32-e}function nt(n){if(typeof TextEncoder<"u")return new TextEncoder().encode(n);let e=new Uint8Array(n.length);for(let t=0;t<n.length;t++)e[t]=n.charCodeAt(t)&255;return e}function en(n){return Array.from(n).map(e=>e.toString(16).padStart(2,"0")).join("")}function tn(n,e){let r=nt(n);r.length>64&&(r=Ne(r));let s=new Uint8Array(64),o=new Uint8Array(64);for(let f=0;f<64;f++)s[f]=(r[f]??0)^54,o[f]=(r[f]??0)^92;let i=nt(e),a=new Uint8Array(64+i.length);a.set(s),a.set(i,64);let c=Ne(a),u=new Uint8Array(96);return u.set(o),u.set(c,64),en(Ne(u))}var O=class extends Error{constructor(e){super(e),this.name="GateError"}},Q=class{threshold;constructor(e=.8){if(e<0||e>1)throw new O(`threshold must be in [0.0, 1.0] \u2014 got ${e}`);this.threshold=e}allows(e){return e>=this.threshold}margin(e){return e-this.threshold}assert(e,t){if(!this.allows(e)){let r=t?` for action '${t}'`:"";throw new O(`Confidence ${e}${r} is below threshold ${this.threshold}`)}}},X=class{_pending=new Map;request(e,t={}){let r=z();return this._pending.set(r,{token:r,action:e,context:t,createdAt:new Date().toISOString(),status:"pending"}),r}approve(e){let t=this._pending.get(e);if(!t)throw new O(`Unknown token: ${e}`);t.status="approved"}deny(e,t){let r=this._pending.get(e);if(!r)throw new O(`Unknown token: ${e}`);r.status="denied",t&&(r.reason=t)}check(e){let t=this._pending.get(e);if(!t)throw new O(`Unknown token: ${e}`);return t.status}get pendingApprovals(){return Array.from(this._pending.values()).filter(e=>e.status==="pending")}getApproval(e){return this._pending.get(e)}clearResolved(){for(let[e,t]of this._pending.entries())t.status!=="pending"&&this._pending.delete(e)}};var Z=class extends Error{constructor(e){super(e),this.name="AuditError"}};function nn(n,e,t,r,s){let o=JSON.stringify({recordId:n,action:e,robotUri:t,timestamp:r,params:s},Object.keys({recordId:n,action:e,robotUri:t,timestamp:r,params:s}).sort());return Oe("rcan-content-hash",o)}function rt(n,e){let{hmac:t,...r}=e,s=JSON.stringify(r,Object.keys(r).sort());return Oe(n,s)}var $=class n{recordId;action;robotUri;confidence;modelIdentity;params;safetyApproved;timestamp;contentHash;previousHash;hmac;constructor(e){this.recordId=e.recordId,this.action=e.action,this.robotUri=e.robotUri,this.confidence=e.confidence,this.modelIdentity=e.modelIdentity,this.params=e.params,this.safetyApproved=e.safetyApproved,this.timestamp=e.timestamp,this.contentHash=e.contentHash,this.previousHash=e.previousHash,this.hmac=e.hmac}static create(e,t,r=null){let s=z(),o=new Date().toISOString(),i=e.params??{},a=e.robotUri??"",c=nn(s,e.action,a,o,i),u={recordId:s,action:e.action,robotUri:a,confidence:e.confidence,modelIdentity:e.modelIdentity,params:i,safetyApproved:e.safetyApproved??!0,timestamp:o,contentHash:c,previousHash:r,hmac:""};return u.hmac=rt(t,u),new n(u)}verify(e){return rt(e,this.toJSON())===this.hmac}toJSON(){return{recordId:this.recordId,action:this.action,robotUri:this.robotUri,confidence:this.confidence,modelIdentity:this.modelIdentity,params:this.params,safetyApproved:this.safetyApproved,timestamp:this.timestamp,contentHash:this.contentHash,previousHash:this.previousHash,hmac:this.hmac}}static fromJSON(e){return new n(e)}},ee=class n{_records=[];_secret;constructor(e){this._secret=e}get records(){return this._records}append(e){let r=this._records[this._records.length-1]?.contentHash??null,s=$.create(e,this._secret,r);return this._records.push(s),s}verifyAll(){let e=[],t=null;for(let r of this._records)r.verify(this._secret)||e.push(`HMAC invalid for record ${r.recordId.slice(0,8)}`),t!==null&&r.previousHash!==t&&e.push(`Chain broken at ${r.recordId.slice(0,8)}: expected prev=${t.slice(0,12)}`),t=r.contentHash;return{valid:e.length===0,count:this._records.length,errors:e}}toJSONL(){return this._records.map(e=>JSON.stringify(e.toJSON())).join(`
2
2
  `)+`
3
- `}static fromJSONL(e,t){let n=new r(t),s=e.trim().split(`
4
- `).filter(o=>o.trim()!=="");for(let o of s){let i=JSON.parse(o);n._records.push(P.fromJSON(i))}return n}};function be(){return{ok:!0,issues:[],warnings:[],info:[]}}function w(r,e){r.ok=!1,r.issues.push(e)}function M(r,e){r.warnings.push(e)}function _(r,e){r.info.push(e)}function De(r){let e=be();try{let t=I.parse(r);_(e,"\u2705 Valid RCAN URI"),_(e,` Registry: ${t.registry}`),_(e,` Manufacturer: ${t.manufacturer}`),_(e,` Model: ${t.model}`),_(e,` Version: ${t.version}`),_(e,` Device ID: ${t.deviceId}`)}catch(t){w(e,`Invalid RCAN URI: ${t instanceof Error?t.message:t}`)}return e}function Pe(r){let e=be(),t;if(typeof r=="string")try{t=JSON.parse(r)}catch{return w(e,"Invalid JSON string"),e}else if(typeof r=="object"&&r!==null)t=r;else return w(e,"Expected object or JSON string"),e;for(let n of["rcan","cmd","target"])(!(n in t)||!t[n])&&w(e,`Missing required field: '${n}'`);if(!e.ok)return e;try{let n=m.fromJSON(t);_(e,`\u2705 RCAN message valid (v${n.rcan})`),_(e,` cmd: ${n.cmd}`),_(e,` target: ${n.target}`),n.confidence!==void 0?_(e,` confidence: ${n.confidence}`):M(e,"No confidence score \u2014 add for RCAN \xA716 AI accountability"),n.isSigned?_(e,` signature: alg=${n.signature?.alg}, kid=${n.signature?.kid}`):M(e,"Message is unsigned (recommended for production)")}catch(n){w(e,`Message validation failed: ${n instanceof Error?n.message:n}`)}return e}function $e(r){let e=be(),t=r.metadata??{},n=r.agent??{},s=r.rcan_protocol??{};for(let i of["rcan_version","metadata","agent"])(!(i in r)||r[i]===void 0||r[i]===null)&&w(e,`Missing required key: '${i}'`);let o=r.rcan_version;if(o&&(/^\d+\.\d+$/.test(o)||w(e,`rcan_version '${o}' must match pattern N.N (e.g. '1.2')`)),t.manufacturer||w(e,"L1: metadata.manufacturer is required (\xA72)"),t.model||w(e,"L1: metadata.model is required (\xA72)"),!t.device_id&&!t.robot_name&&w(e,"L1: metadata.device_id (or robot_name) is required (\xA72)"),s.jwt_auth?.enabled||M(e,"L2: jwt_auth not enabled (required for L2 conformance, \xA78)"),(!n.confidence_gates||n.confidence_gates.length===0)&&M(e,"L2: confidence_gates not configured (\xA716)"),(!n.hitl_gates||n.hitl_gates.length===0)&&M(e,"L3: hitl_gates not configured (\xA716)"),n.commitment_chain?.enabled||M(e,"L3: commitment_chain not enabled (\xA716)"),t.rrn?_(e,`\u2705 RRN registered: ${t.rrn}`):M(e,"Robot not registered \u2014 visit rcan.dev/registry/register"),e.ok&&e.issues.length===0){let i=!e.warnings.some(g=>g.startsWith("L1")),c=i&&!e.warnings.some(g=>g.startsWith("L2")),u=c&&!e.warnings.some(g=>g.startsWith("L3"))?"L3":c?"L2":i?"L1":"FAIL";_(e,`\u2705 Config valid \u2014 conformance level: ${u}`)}return e}var y=class extends Error{constructor(e){super(e),this.name="RCANError",Object.setPrototypeOf(this,new.target.prototype)}},W=class extends y{constructor(e){super(e),this.name="RCANAddressError",Object.setPrototypeOf(this,new.target.prototype)}},Q=class extends y{constructor(e){super(e),this.name="RCANValidationError",Object.setPrototypeOf(this,new.target.prototype)}},z=class extends y{constructor(t,n,s,o){super(t);this.gateType=n;this.value=s;this.threshold=o;this.name="RCANGateError",Object.setPrototypeOf(this,new.target.prototype)}},X=class extends y{constructor(e){super(e),this.name="RCANSignatureError",Object.setPrototypeOf(this,new.target.prototype)}},U=class extends y{constructor(e){super(e),this.name="RCANRegistryError",Object.setPrototypeOf(this,new.target.prototype)}},D=class r extends y{constructor(t,n){super(t);this.nodeUrl=n;this.name="RCANNodeError",Object.setPrototypeOf(this,r.prototype)}},A=class r extends D{constructor(t,n){super(`RRN not found in federation: ${t}`,n);this.rrn=t;this.name="RCANNodeNotFoundError",Object.setPrototypeOf(this,r.prototype)}},h=class r extends D{constructor(t,n,s){super(t,n);this.cause=s;this.name="RCANNodeSyncError",Object.setPrototypeOf(this,r.prototype)}},$=class r extends D{reason;constructor(e,t){super(`Node trust verification failed: ${e}`,t),this.name="RCANNodeTrustError",this.reason=e,Object.setPrototypeOf(this,r.prototype)}},Z=class r extends y{constructor(e,t){super(`VERSION_INCOMPATIBLE: incoming=${e}, local=${t}`),this.name="RCANVersionIncompatibleError",Object.setPrototypeOf(this,r.prototype)}},ee=class r extends y{constructor(e){super(`REPLAY_DETECTED: ${e}`),this.name="RCANReplayAttackError",Object.setPrototypeOf(this,r.prototype)}},te=class r extends y{constructor(e){super(`DELEGATION_CHAIN_ERROR: ${e}`),this.name="RCANDelegationChainError",Object.setPrototypeOf(this,r.prototype)}},re=class r extends y{constructor(e){super(`CONFIG_AUTH_ERROR: ${e}`),this.name="RCANConfigAuthorizationError",Object.setPrototypeOf(this,r.prototype)}};var bt="https://rcan-spec.pages.dev",ne=class{baseUrl;apiKey;timeout;constructor(e){this.baseUrl=(e?.baseUrl??bt).replace(/\/$/,""),this.apiKey=e?.apiKey,this.timeout=e?.timeout??1e4}async _fetch(e,t={}){let n=`${this.baseUrl}${e}`,s=new AbortController,o=setTimeout(()=>s.abort(),this.timeout);try{return await fetch(n,{...t,signal:s.signal,headers:{"Content-Type":"application/json",...t.headers??{}}})}finally{clearTimeout(o)}}_authHeaders(){if(!this.apiKey)throw new U("API key required for write operations. Pass apiKey to RegistryClient.");return{Authorization:`Bearer ${this.apiKey}`}}async _checkResponse(e){if(!e.ok){let t=`Registry API error: ${e.status}`;try{let n=await e.json();n?.error&&(t=n.error)}catch{}throw new U(t)}return await e.json()}async register(e){let t=await this._fetch("/api/v1/robots",{method:"POST",body:JSON.stringify(e)});return this._checkResponse(t)}async get(e){let t=await this._fetch(`/api/v1/robots/${encodeURIComponent(e)}`);return this._checkResponse(t)}async list(e){let t=new URLSearchParams;e?.limit!==void 0&&t.set("limit",String(e.limit)),e?.offset!==void 0&&t.set("offset",String(e.offset)),e?.tier&&t.set("tier",e.tier);let n=t.toString()?`?${t}`:"",s=await this._fetch(`/api/v1/robots${n}`);return this._checkResponse(s)}async patch(e,t){let n=await this._fetch(`/api/v1/robots/${encodeURIComponent(e)}`,{method:"PATCH",headers:this._authHeaders(),body:JSON.stringify(t)});return this._checkResponse(n)}async delete(e){let t=await this._fetch(`/api/v1/robots/${encodeURIComponent(e)}`,{method:"DELETE",headers:this._authHeaders()});t.ok||await this._checkResponse(t)}async search(e){let t=new URLSearchParams;e.q&&t.set("q",e.q),e.manufacturer&&t.set("manufacturer",e.manufacturer),e.model&&t.set("model",e.model),e.tier&&t.set("tier",e.tier);let n=t.toString()?`?${t}`:"",s=await this._fetch(`/api/v1/robots/search${n}`);if(!s.ok){let i=await this._fetch(`/api/v1/robots${n}`),c=await this._checkResponse(i);return"robots"in c?c.robots:"results"in c&&c.results?c.results:[]}let o=await s.json();return Array.isArray(o)?o:"results"in o&&o.results?o.results:"robots"in o?o.robots:[]}};var vt="https://rcan.dev",xt="/.well-known/rcan-node.json",wt=new Set(["root","authoritative","resolver","cache"]);function Et(r){let e=r.match(/^RRN-([A-Z0-9]{2,8})-(\d{8,16})$/);if(e)return{type:"delegated",prefix:e[1],serial:e[2]};let t=r.match(/^RRN-(\d{8,16})$/);return t?{type:"root",serial:t[1]}:null}var se=class{rootUrl;timeoutMs;constructor(e=vt,t=1e4){this.rootUrl=e.replace(/\/$/,""),this.timeoutMs=t}async _fetch(e){let t=new AbortController,n=setTimeout(()=>t.abort(),this.timeoutMs);try{return await globalThis.fetch(e,{signal:t.signal})}catch(s){throw s instanceof Error&&s.name==="AbortError"?new h(`Request timed out: ${e}`,e,s):new h(`Network error fetching ${e}: ${s.message}`,e,s instanceof Error?s:void 0)}finally{clearTimeout(n)}}async getNodeManifest(e){let t=`${e.replace(/\/$/,"")}${xt}`,n=await this._fetch(t);if(!n.ok)throw n.status===404?new A(t,e):new h(`Failed to fetch node manifest from ${e}: HTTP ${n.status}`,e);let s;try{s=await n.json()}catch(o){throw new h(`Invalid JSON in node manifest from ${e}`,e,o instanceof Error?o:void 0)}if(!this.verifyNode(s))throw new $("missing_pubkey",e);return s}async listNodes(e){let t=e?`?prefix=${encodeURIComponent(e)}`:"",n=`${this.rootUrl}/api/v1/nodes${t}`,s=await this._fetch(n);if(!s.ok)throw new h(`Failed to list nodes from ${n}: HTTP ${s.status}`,n);let o;try{o=await s.json()}catch(i){throw new h(`Invalid JSON in nodes list from ${n}`,n,i instanceof Error?i:void 0)}return Array.isArray(o)?o:o&&typeof o=="object"&&"nodes"in o?o.nodes:[]}async discover(e){let t=Et(e);if(!t)throw new A(e,this.rootUrl);if(t.type==="root")return this.getNodeManifest(this.rootUrl);let n=await this.listNodes(t.prefix);if(n.length===0)throw new A(e,this.rootUrl);return n[0]}async resolve(e){let t=`${this.rootUrl}/api/v1/resolve/${encodeURIComponent(e)}`,n;try{n=await this._fetch(t)}catch(c){throw c}if(n.ok)try{return await n.json()}catch(c){throw new h(`Invalid JSON in resolve response for ${e}`,this.rootUrl,c instanceof Error?c:void 0)}if(n.status!==404)throw new h(`Unexpected HTTP ${n.status} resolving ${e}`,this.rootUrl);let s=await this.discover(e),o=`${s.api_base.replace(/\/$/,"")}/robots/${encodeURIComponent(e)}`,i=await this._fetch(o);if(!i.ok)throw i.status===404?new A(e,s.api_base):new h(`HTTP ${i.status} from authoritative node for ${e}`,s.api_base);try{return await i.json()}catch(c){throw new h(`Invalid JSON in fallback resolve response for ${e}`,s.api_base,c instanceof Error?c:void 0)}}verifyNode(e){if(!e||typeof e!="object")return!1;let t=e;return!(typeof t.rcan_node_version!="string"||!t.rcan_node_version||typeof t.node_type!="string"||!wt.has(t.node_type)||typeof t.operator!="string"||!t.operator||typeof t.namespace_prefix!="string"||!t.namespace_prefix||typeof t.public_key!="string"||!t.public_key.startsWith("ed25519:")||typeof t.api_base!="string"||!t.api_base.startsWith("https://"))}};var Ct="https://rcan.dev/schemas",ve=new Map;async function oe(r){if(ve.has(r))return ve.get(r);try{let e=new AbortController,t=setTimeout(()=>e.abort(),5e3),n=await fetch(`${Ct}/${r}`,{signal:e.signal});if(clearTimeout(t),!n.ok)return null;let s=await n.json();return ve.set(r,s),s}catch{return null}}async function qe(r){let e=await oe("rcan-config.schema.json");if(!e)return{valid:!0,skipped:!0};let t=[];if(typeof r!="object"||r===null)return{valid:!1,errors:["Config must be an object"]};let n=r,s=e.required??[];for(let o of s)o in n||t.push(`Missing required field: ${o}`);return t.length===0?{valid:!0}:{valid:!1,errors:t}}async function je(r){let e=await oe("rcan-node.schema.json");if(!e)return{valid:!0,skipped:!0};let t=[];if(typeof r!="object"||r===null)return{valid:!1,errors:["Manifest must be an object"]};let n=r,s=e.required??[];for(let o of s)o in n||t.push(`Missing required field: ${o}`);return t.length===0?{valid:!0}:{valid:!1,errors:t}}var xe=(n=>(n[n.FIRE_AND_FORGET=0]="FIRE_AND_FORGET",n[n.ACKNOWLEDGED=1]="ACKNOWLEDGED",n[n.EXACTLY_ONCE=2]="EXACTLY_ONCE",n))(xe||{}),ie=class r extends Error{constructor(e){super(`ACK timeout for message ${e} \u2014 safety halt required`),this.name="QoSAckTimeoutError",Object.setPrototypeOf(this,r.prototype)}},ae=class{_send;_waitForAck;constructor(e,t){this._send=e,this._waitForAck=t}async sendWithQoS(e,t={}){let n=t.qos??0,s=t.maxRetries??3,o=t.initialBackoffMs??100,i=t.ackTimeoutMs??500;if(n===0)return await this._send(e),{delivered:!0,attempts:1,reason:"fire-and-forget"};let c=e.message_id??e.msg_id??"unknown",d=0,u=o;for(;d<=s;){if(await this._send(e),d++,await this._waitForAck(c,i))return{delivered:!0,attempts:d,reason:n===2?"exactly-once":"acknowledged"};if(d>s)break;await Nt(u),u=Math.min(u*2,5e3)}return{delivered:!1,attempts:d,reason:`ACK not received after ${s} retries`}}};function Le(r,e){return{message_type:6,ruri:r,safety_event:"ESTOP",reason:e.slice(0,512),timestamp_ms:Date.now(),message_id:At(),qos:2}}function At(){if(typeof crypto<"u"&&typeof crypto.randomUUID=="function")return crypto.randomUUID();let r=Array.from({length:16},()=>Math.floor(Math.random()*256));r[6]=r[6]&15|64,r[8]=r[8]&63|128;let e=r.map(t=>t.toString(16).padStart(2,"0"));return`${e.slice(0,4).join("")}-${e.slice(4,6).join("")}-${e.slice(6,8).join("")}-${e.slice(8,10).join("")}-${e.slice(10).join("")}`}function Nt(r){return new Promise(e=>setTimeout(e,r))}var we=6;function ce(){if(typeof crypto<"u"&&typeof crypto.randomUUID=="function")return crypto.randomUUID();let r=Array.from({length:16},()=>Math.floor(Math.random()*256));r[6]=r[6]&15|64,r[8]=r[8]&63|128;let e=r.map(t=>t.toString(16).padStart(2,"0"));return`${e.slice(0,4).join("")}-${e.slice(4,6).join("")}-${e.slice(6,8).join("")}-${e.slice(8,10).join("")}-${e.slice(10).join("")}`}function Ke(r,e){return{message_type:6,ruri:r,safety_event:"ESTOP",reason:e.slice(0,512),timestamp_ms:Date.now(),message_id:ce(),qos:2}}function He(r,e){return{message_type:6,ruri:r,safety_event:"STOP",reason:e.slice(0,512),timestamp_ms:Date.now(),message_id:ce()}}function Ve(r,e){return{message_type:6,ruri:r,safety_event:"RESUME",reason:e.slice(0,512),timestamp_ms:Date.now(),message_id:ce()}}function Fe(r){return typeof r=="object"&&r!==null&&r.message_type===we}function Je(r){let e=[];return r.message_type!==6&&e.push("message_type must be 6"),r.ruri||e.push("ruri is required"),["ESTOP","STOP","RESUME"].includes(r.safety_event??"")||e.push("safety_event must be ESTOP, STOP, or RESUME"),(!r.reason||r.reason.length===0)&&e.push("reason is required"),r.message_id||e.push("message_id is required"),(!r.timestamp_ms||r.timestamp_ms<=0)&&e.push("timestamp_ms must be positive"),e}function Ye(r,e,t){return{message_type:11,ruri:r,disclosure:e,timestamp_ms:Date.now(),message_id:ce(),delegation_chain:t}}var de=class{windowSeconds;maxSize;_seen;constructor(e=30,t=1e4){this.windowSeconds=e,this.maxSize=t,this._seen=new Map}checkAndRecord(e,t,n=!1){let s=Date.now();this._evict(s);let o=n?Math.min(this.windowSeconds,10):this.windowSeconds,i=Ot(t);if(i===null)return{allowed:!1,reason:`invalid timestamp format: ${t}`};let c=s-i,d=o*1e3;if(c>d)return{allowed:!1,reason:`message too old: age=${Math.round(c/1e3)}s > window=${o}s`};if(i>s+5e3)return{allowed:!1,reason:"message timestamp is in the future"};if(this._seen.has(e))return{allowed:!1,reason:`replay detected: msg_id ${e} already seen`};if(this._seen.size>=this.maxSize){let g=this._seen.keys().next().value;this._seen.delete(g)}let u=s+d;return this._seen.set(e,u),{allowed:!0,reason:"ok"}}_evict(e){for(let[t,n]of this._seen)n<=e&&this._seen.delete(t)}get size(){return this._seen.size}};function Ge(r,e){let t=r,n=t.message_id??t.msg_id;if(!n)return{valid:!1,reason:"missing message_id / msg_id"};let s;if(typeof t.timestamp_ms=="number"?s=String(t.timestamp_ms/1e3):t.timestamp!==void 0&&(s=String(t.timestamp)),!s)return{valid:!1,reason:"missing timestamp"};let o=t.message_type===6||t.message_type===6,i=e.checkAndRecord(n,s,o);return{valid:i.allowed,reason:i.reason}}function Ot(r){if(r.includes("T")||r.includes("-")){let t=new Date(r);if(!isNaN(t.getTime()))return t.getTime()}let e=parseFloat(r);return isNaN(e)?null:e>1e12?e:e*1e3}var L=class r extends Error{offsetSeconds;constructor(e,t){super(`Clock drift too large: offset=${e.toFixed(3)}s > max=${t}s`),this.name="ClockDriftError",this.offsetSeconds=e,Object.setPrototypeOf(this,r.prototype)}};async function Ee(r){let e=r??"https://worldtimeapi.org/api/ip";try{let t=Date.now(),n=await fetch(e,{method:"HEAD",signal:AbortSignal.timeout(3e3)}),s=Date.now(),o=n.headers.get("Date")??n.headers.get("date");if(!o)return{synchronized:!0,offsetSeconds:0,source:"assumed (no Date header)"};let i=new Date(o).getTime();if(isNaN(i))return{synchronized:!0,offsetSeconds:0,source:"assumed (unparseable Date header)"};let d=((t+s)/2-i)/1e3;return{synchronized:Math.abs(d)<=5,offsetSeconds:d,source:e}}catch{return{synchronized:!0,offsetSeconds:0,source:"assumed (network unavailable)"}}}async function Be(r=5){let e=await Ee();if(!e.synchronized||Math.abs(e.offsetSeconds)>r)throw new L(e.offsetSeconds,r)}async function kt(r){let e=JSON.stringify(r,Object.keys(r).sort());if(typeof crypto<"u"&&crypto.subtle){let n=new TextEncoder().encode(e),s=await crypto.subtle.digest("SHA-256",n);return Array.from(new Uint8Array(s)).map(o=>o.toString(16).padStart(2,"0")).join("")}let t=2166136261;for(let n=0;n<e.length;n++)t^=e.charCodeAt(n),t=t*16777619>>>0;return t.toString(16).padStart(8,"0")}async function We(r,e,t,n="rcan://local/config",s=!1){let o=await kt(r);return new m({rcan:"1.5",cmd:"CONFIG_UPDATE",target:n,params:{message_type:5,diff:r,rollback:t,scope:e,config_hash:o,safety_overrides:s}})}function Qe(r){let e=r.params;return!e.diff||typeof e.diff!="object"?{valid:!1,reason:"missing required field: params.diff"}:!e.config_hash||typeof e.config_hash!="string"?{valid:!1,reason:"missing required field: params.config_hash"}:"rollback"in e?e.safety_overrides===!0&&e.scope!=="creator"?{valid:!1,reason:"safety_overrides=true requires scope=creator (owner is insufficient)"}:{valid:!0,reason:"ok"}:{valid:!1,reason:"missing required field: params.rollback"}}function It(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).slice(2)}`}var ue=class{_keys=[];addKey(e){this._keys.push(e)}getJWKS(){return{keys:[...this._keys]}}findKey(e){return this._keys.find(t=>t.kid===e)}isKeyValid(e,t){let n=this.findKey(e);if(!n)return!1;let s=(t??Date.now())/1e3;return!(n.revoked_at!==void 0&&n.revoked_at<=s||n.exp!==void 0&&n.exp<s)}expireKey(e,t){let n=this.findKey(e);n&&(n.exp=t??Math.floor(Date.now()/1e3))}revokeKey(e){let t=this.findKey(e);t&&(t.revoked_at=Math.floor(Date.now()/1e3))}validKeys(e){return this._keys.filter(t=>this.isKeyValid(t.kid,e))}};function ze(r,e,t=120,n="rcan://local/keys"){let s=It().slice(0,8);return new m({rcan:"1.5",cmd:"KEY_ROTATION",target:n,params:{message_type:5,new_public_key:r,new_kid:s,old_kid:e,overlap_seconds:t,initiated_at:new Date().toISOString()},keyId:s})}function Tt(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).slice(2)}`}function fe(r){let e=r.requestId??Tt();return new m({rcan:"1.5",cmd:"CONSENT_REQUEST",target:r.targetRuri,params:{message_type:20,requester_ruri:r.requesterRuri,requester_owner:r.requesterOwner,target_ruri:r.targetRuri,requested_scopes:r.requestedScopes,duration_hours:r.durationHours,justification:r.justification,request_id:e,consent_type:r.consentType??"cross_robot",data_categories:r.dataCategories??[]}})}function le(r){let e=r.expiresAt??new Date(Date.now()+864e5).toISOString();return new m({rcan:"1.5",cmd:"CONSENT_GRANT",target:"rcan://local/consent",params:{message_type:21,request_id:r.requestId,granted_scopes:r.grantedScopes??[],expires_at:e,reason:r.reason??"approved"}})}function me(r){return new m({rcan:"1.5",cmd:"CONSENT_DENY",target:"rcan://local/consent",params:{message_type:22,request_id:r.requestId,reason:r.reason??"denied"}})}function Xe(r){let e=r.cmd,t=r.params,n=t.message_type;return e==="CONSENT_REQUEST"?n!==20?{valid:!1,reason:"message_type must be CONSENT_REQUEST (20)"}:t.requester_ruri?t.target_ruri?!t.requested_scopes||!Array.isArray(t.requested_scopes)||t.requested_scopes.length===0?{valid:!1,reason:"requested_scopes must be a non-empty array"}:t.request_id?t.justification?{valid:!0,reason:"ok"}:{valid:!1,reason:"missing justification"}:{valid:!1,reason:"missing request_id"}:{valid:!1,reason:"missing target_ruri"}:{valid:!1,reason:"missing requester_ruri"}:e==="CONSENT_GRANT"?n!==21?{valid:!1,reason:"message_type must be CONSENT_GRANT (21)"}:t.request_id?t.expires_at?{valid:!0,reason:"ok"}:{valid:!1,reason:"missing expires_at"}:{valid:!1,reason:"missing request_id"}:e==="CONSENT_DENY"?n!==22?{valid:!1,reason:"message_type must be CONSENT_DENY (22)"}:t.request_id?{valid:!0,reason:"ok"}:{valid:!1,reason:"missing request_id"}:{valid:!1,reason:`unknown consent command: ${e}`}}var Mt=3600*1e3,K=class{_cache=new Map;get(e,t){let n=this._cache.get(e);if(!n)return;let s=t??Date.now();if(n.cachedUntil!==void 0&&n.cachedUntil<s){this._cache.delete(e);return}return n}set(e,t){let n=t??Date.now();this._cache.set(e.rrn,{...e,cachedUntil:n+Mt})}invalidate(e){this._cache.delete(e)}get size(){return this._cache.size}};async function Ze(r,e,t){let n=t??new K,s=n.get(r);if(s)return s;let o=`${e.replace(/\/$/,"")}/api/v1/robots/${encodeURIComponent(r)}/revocation-status`;try{let i=await fetch(o,{signal:AbortSignal.timeout(5e3)});if(!i.ok){let u={rrn:r,status:"active",reason:`registry returned ${i.status}`};return n.set(u),u}let c=await i.json(),d={rrn:r,status:c.status??"active",revokedAt:c.revokedAt,reason:c.reason,authority:c.authority};return n.set(d),d}catch{return{rrn:r,status:"active",reason:"network unavailable"}}}function et(r,e){return new m({rcan:"1.5",cmd:"ROBOT_REVOCATION",target:"rcan://broadcast/revocation",params:{message_type:19,rrn:r,reason:e,revoked_at:new Date().toISOString()}})}var Ce=(o=>(o.VIDEO="video",o.AUDIO="audio",o.LOCATION="location",o.BIOMETRIC="biometric",o.TELEMETRY="telemetry",o))(Ce||{});function tt(r){return fe({requesterRuri:r.requesterRuri,requesterOwner:r.requesterOwner,targetRuri:r.targetRuri,requestedScopes:["training_data"],durationHours:r.durationHours,justification:r.justification,requestId:r.requestId,consentType:"training_data",dataCategories:r.dataCategories})}function rt(r){return le(r)}function nt(r){return me(r)}function st(r){if(r.params.message_type!==10)return{valid:!1,reason:"not a TRAINING_DATA message"};let e=r.params.consent_token;return!e||typeof e!="string"||e.trim()===""?{valid:!1,reason:"TRAINING_DATA message missing consent_token (\xA717)"}:{valid:!0,reason:"ok"}}var ge=class{crossOwnerGraceS;keyTtlS;_cachedKeys=[];constructor(e=3600,t=86400){this.crossOwnerGraceS=e,this.keyTtlS=t}canAcceptCommand(e,t,n,s=!0,o=!1,i,c){if(e&&e.message_type===6&&e.safety_event==="ESTOP")return{allowed:!0,reason:"ESTOP always accepted (Protocol 66)"};if(!t)return{allowed:!0,reason:"online mode"};if(!n)return{allowed:!1,reason:"offline mode: cross-network commands blocked"};if(!s)return{allowed:!1,reason:"offline mode: only owner-role commands accepted from local network"};if(o&&i!==void 0){let u=((c??Date.now())-i)/1e3;if(u>this.crossOwnerGraceS)return{allowed:!1,reason:`offline mode: cross-owner grace period expired (${Math.round(u)}s > ${this.crossOwnerGraceS}s)`}}return{allowed:!0,reason:"offline mode: owner command on local network accepted"}}cacheKey(e,t){let n=t??Date.now();this._cachedKeys=this._cachedKeys.filter(s=>s.kid!==e.kid),this._cachedKeys.push({...e,cachedAtMs:n,ttlSeconds:this.keyTtlS})}getCachedKey(e,t){let n=t??Date.now(),s=this._cachedKeys.find(i=>i.kid===e);if(!s)return;if((n-s.cachedAtMs)/1e3>s.ttlSeconds){this._cachedKeys=this._cachedKeys.filter(i=>i.kid!==e);return}return s}getManifestFields(e,t){if(e===void 0)return{offline_mode:!1,offline_since_s:0};let n=t??Date.now();return{offline_mode:!0,offline_since_s:Math.round((n-e)/1e3)}}};var Ae=(p=>(p.SENSOR_PROXIMITY_FAILURE="SENSOR_PROXIMITY_FAILURE",p.SENSOR_CAMERA_FAILURE="SENSOR_CAMERA_FAILURE",p.SENSOR_IMU_FAILURE="SENSOR_IMU_FAILURE",p.MOTOR_OVERCURRENT="MOTOR_OVERCURRENT",p.MOTOR_OVERTEMP="MOTOR_OVERTEMP",p.MOTOR_STALL="MOTOR_STALL",p.BATTERY_CRITICAL="BATTERY_CRITICAL",p.BATTERY_LOW="BATTERY_LOW",p.NETWORK_TIMEOUT="NETWORK_TIMEOUT",p.NETWORK_REGISTRY_UNREACHABLE="NETWORK_REGISTRY_UNREACHABLE",p.SAFETY_ESTOP_STUCK="SAFETY_ESTOP_STUCK",p.SAFETY_WATCHDOG_TIMEOUT="SAFETY_WATCHDOG_TIMEOUT",p.UNKNOWN="UNKNOWN",p))(Ae||{});function ot(r){return new m({rcan:"1.5",cmd:"FAULT_REPORT",target:r.target??"rcan://local/fault",params:{message_type:26,fault_code:r.faultCode,severity:r.severity,subsystem:r.subsystem,affects_safety:r.affectsSafety,safe_to_continue:r.safeToContinue,description:r.description??"",reported_at:new Date().toISOString()}})}var Ut="0.5.0",Dt="1.5";return yt(Pt);})();
3
+ `}static fromJSONL(e,t){let r=new n(t),s=e.trim().split(`
4
+ `).filter(o=>o.trim()!=="");for(let o of s){let i=JSON.parse(o);r._records.push($.fromJSON(i))}return r}};function ke(){return{ok:!0,issues:[],warnings:[],info:[]}}function w(n,e){n.ok=!1,n.issues.push(e)}function P(n,e){n.warnings.push(e)}function _(n,e){n.info.push(e)}function st(n){let e=ke();try{let t=U.parse(n);_(e,"\u2705 Valid RCAN URI"),_(e,` Registry: ${t.registry}`),_(e,` Manufacturer: ${t.manufacturer}`),_(e,` Model: ${t.model}`),_(e,` Version: ${t.version}`),_(e,` Device ID: ${t.deviceId}`)}catch(t){w(e,`Invalid RCAN URI: ${t instanceof Error?t.message:t}`)}return e}function ot(n){let e=ke(),t;if(typeof n=="string")try{t=JSON.parse(n)}catch{return w(e,"Invalid JSON string"),e}else if(typeof n=="object"&&n!==null)t=n;else return w(e,"Expected object or JSON string"),e;for(let r of["rcan","cmd","target"])(!(r in t)||!t[r])&&w(e,`Missing required field: '${r}'`);if(!e.ok)return e;try{let r=l.fromJSON(t);_(e,`\u2705 RCAN message valid (v${r.rcan})`),_(e,` cmd: ${r.cmd}`),_(e,` target: ${r.target}`),r.confidence!==void 0?_(e,` confidence: ${r.confidence}`):P(e,"No confidence score \u2014 add for RCAN \xA716 AI accountability"),r.isSigned?_(e,` signature: alg=${r.signature?.alg}, kid=${r.signature?.kid}`):P(e,"Message is unsigned (recommended for production)")}catch(r){w(e,`Message validation failed: ${r instanceof Error?r.message:r}`)}return e}function it(n){let e=ke(),t=n.metadata??{},r=n.agent??{},s=n.rcan_protocol??{};for(let i of["rcan_version","metadata","agent"])(!(i in n)||n[i]===void 0||n[i]===null)&&w(e,`Missing required key: '${i}'`);let o=n.rcan_version;if(o&&(/^\d+\.\d+$/.test(o)||w(e,`rcan_version '${o}' must match pattern N.N (e.g. '1.2')`)),t.manufacturer||w(e,"L1: metadata.manufacturer is required (\xA72)"),t.model||w(e,"L1: metadata.model is required (\xA72)"),!t.device_id&&!t.robot_name&&w(e,"L1: metadata.device_id (or robot_name) is required (\xA72)"),s.jwt_auth?.enabled||P(e,"L2: jwt_auth not enabled (required for L2 conformance, \xA78)"),(!r.confidence_gates||r.confidence_gates.length===0)&&P(e,"L2: confidence_gates not configured (\xA716)"),(!r.hitl_gates||r.hitl_gates.length===0)&&P(e,"L3: hitl_gates not configured (\xA716)"),r.commitment_chain?.enabled||P(e,"L3: commitment_chain not enabled (\xA716)"),t.rrn?_(e,`\u2705 RRN registered: ${t.rrn}`):P(e,"Robot not registered \u2014 visit rcan.dev/registry/register"),e.ok&&e.issues.length===0){let i=!e.warnings.some(f=>f.startsWith("L1")),a=i&&!e.warnings.some(f=>f.startsWith("L2")),u=a&&!e.warnings.some(f=>f.startsWith("L3"))?"L3":a?"L2":i?"L1":"FAIL";_(e,`\u2705 Config valid \u2014 conformance level: ${u}`)}return e}var R=class extends Error{constructor(e){super(e),this.name="RCANError",Object.setPrototypeOf(this,new.target.prototype)}},te=class extends R{constructor(e){super(e),this.name="RCANAddressError",Object.setPrototypeOf(this,new.target.prototype)}},ne=class extends R{constructor(e){super(e),this.name="RCANValidationError",Object.setPrototypeOf(this,new.target.prototype)}},re=class extends R{constructor(t,r,s,o){super(t);this.gateType=r;this.value=s;this.threshold=o;this.name="RCANGateError",Object.setPrototypeOf(this,new.target.prototype)}},se=class extends R{constructor(e){super(e),this.name="RCANSignatureError",Object.setPrototypeOf(this,new.target.prototype)}},D=class extends R{constructor(e){super(e),this.name="RCANRegistryError",Object.setPrototypeOf(this,new.target.prototype)}},L=class n extends R{constructor(t,r){super(t);this.nodeUrl=r;this.name="RCANNodeError",Object.setPrototypeOf(this,n.prototype)}},k=class n extends L{constructor(t,r){super(`RRN not found in federation: ${t}`,r);this.rrn=t;this.name="RCANNodeNotFoundError",Object.setPrototypeOf(this,n.prototype)}},y=class n extends L{constructor(t,r,s){super(t,r);this.cause=s;this.name="RCANNodeSyncError",Object.setPrototypeOf(this,n.prototype)}},j=class n extends L{reason;constructor(e,t){super(`Node trust verification failed: ${e}`,t),this.name="RCANNodeTrustError",this.reason=e,Object.setPrototypeOf(this,n.prototype)}},oe=class n extends R{constructor(e,t){super(`VERSION_INCOMPATIBLE: incoming=${e}, local=${t}`),this.name="RCANVersionIncompatibleError",Object.setPrototypeOf(this,n.prototype)}},ie=class n extends R{constructor(e){super(`REPLAY_DETECTED: ${e}`),this.name="RCANReplayAttackError",Object.setPrototypeOf(this,n.prototype)}},ae=class n extends R{constructor(e){super(`DELEGATION_CHAIN_ERROR: ${e}`),this.name="RCANDelegationChainError",Object.setPrototypeOf(this,n.prototype)}},ce=class n extends R{constructor(e){super(`CONFIG_AUTH_ERROR: ${e}`),this.name="RCANConfigAuthorizationError",Object.setPrototypeOf(this,n.prototype)}};var rn="https://rcan-spec.pages.dev",de=class{baseUrl;apiKey;timeout;constructor(e){this.baseUrl=(e?.baseUrl??rn).replace(/\/$/,""),this.apiKey=e?.apiKey,this.timeout=e?.timeout??1e4}async _fetch(e,t={}){let r=`${this.baseUrl}${e}`,s=new AbortController,o=setTimeout(()=>s.abort(),this.timeout);try{return await fetch(r,{...t,signal:s.signal,headers:{"Content-Type":"application/json",...t.headers??{}}})}finally{clearTimeout(o)}}_authHeaders(){if(!this.apiKey)throw new D("API key required for write operations. Pass apiKey to RegistryClient.");return{Authorization:`Bearer ${this.apiKey}`}}async _checkResponse(e){if(!e.ok){let t=`Registry API error: ${e.status}`;try{let r=await e.json();r?.error&&(t=r.error)}catch{}throw new D(t)}return await e.json()}async register(e){let t=await this._fetch("/api/v1/robots",{method:"POST",body:JSON.stringify(e)});return this._checkResponse(t)}async get(e){let t=await this._fetch(`/api/v1/robots/${encodeURIComponent(e)}`);return this._checkResponse(t)}async list(e){let t=new URLSearchParams;e?.limit!==void 0&&t.set("limit",String(e.limit)),e?.offset!==void 0&&t.set("offset",String(e.offset)),e?.tier&&t.set("tier",e.tier);let r=t.toString()?`?${t}`:"",s=await this._fetch(`/api/v1/robots${r}`);return this._checkResponse(s)}async patch(e,t){let r=await this._fetch(`/api/v1/robots/${encodeURIComponent(e)}`,{method:"PATCH",headers:this._authHeaders(),body:JSON.stringify(t)});return this._checkResponse(r)}async delete(e){let t=await this._fetch(`/api/v1/robots/${encodeURIComponent(e)}`,{method:"DELETE",headers:this._authHeaders()});t.ok||await this._checkResponse(t)}async search(e){let t=new URLSearchParams;e.q&&t.set("q",e.q),e.manufacturer&&t.set("manufacturer",e.manufacturer),e.model&&t.set("model",e.model),e.tier&&t.set("tier",e.tier);let r=t.toString()?`?${t}`:"",s=await this._fetch(`/api/v1/robots/search${r}`);if(!s.ok){let i=await this._fetch(`/api/v1/robots${r}`),a=await this._checkResponse(i);return"robots"in a?a.robots:"results"in a&&a.results?a.results:[]}let o=await s.json();return Array.isArray(o)?o:"results"in o&&o.results?o.results:"robots"in o?o.robots:[]}};var sn="https://rcan.dev",on="/.well-known/rcan-node.json",an=new Set(["root","authoritative","resolver","cache"]);function cn(n){let e=n.match(/^RRN-([A-Z0-9]{2,8})-(\d{8,16})$/);if(e)return{type:"delegated",prefix:e[1],serial:e[2]};let t=n.match(/^RRN-(\d{8,16})$/);return t?{type:"root",serial:t[1]}:null}var ue=class{rootUrl;timeoutMs;constructor(e=sn,t=1e4){this.rootUrl=e.replace(/\/$/,""),this.timeoutMs=t}async _fetch(e){let t=new AbortController,r=setTimeout(()=>t.abort(),this.timeoutMs);try{return await globalThis.fetch(e,{signal:t.signal})}catch(s){throw s instanceof Error&&s.name==="AbortError"?new y(`Request timed out: ${e}`,e,s):new y(`Network error fetching ${e}: ${s.message}`,e,s instanceof Error?s:void 0)}finally{clearTimeout(r)}}async getNodeManifest(e){let t=`${e.replace(/\/$/,"")}${on}`,r=await this._fetch(t);if(!r.ok)throw r.status===404?new k(t,e):new y(`Failed to fetch node manifest from ${e}: HTTP ${r.status}`,e);let s;try{s=await r.json()}catch(o){throw new y(`Invalid JSON in node manifest from ${e}`,e,o instanceof Error?o:void 0)}if(!this.verifyNode(s))throw new j("missing_pubkey",e);return s}async listNodes(e){let t=e?`?prefix=${encodeURIComponent(e)}`:"",r=`${this.rootUrl}/api/v1/nodes${t}`,s=await this._fetch(r);if(!s.ok)throw new y(`Failed to list nodes from ${r}: HTTP ${s.status}`,r);let o;try{o=await s.json()}catch(i){throw new y(`Invalid JSON in nodes list from ${r}`,r,i instanceof Error?i:void 0)}return Array.isArray(o)?o:o&&typeof o=="object"&&"nodes"in o?o.nodes:[]}async discover(e){let t=cn(e);if(!t)throw new k(e,this.rootUrl);if(t.type==="root")return this.getNodeManifest(this.rootUrl);let r=await this.listNodes(t.prefix);if(r.length===0)throw new k(e,this.rootUrl);return r[0]}async resolve(e){let t=`${this.rootUrl}/api/v1/resolve/${encodeURIComponent(e)}`,r;try{r=await this._fetch(t)}catch(a){throw a}if(r.ok)try{return await r.json()}catch(a){throw new y(`Invalid JSON in resolve response for ${e}`,this.rootUrl,a instanceof Error?a:void 0)}if(r.status!==404)throw new y(`Unexpected HTTP ${r.status} resolving ${e}`,this.rootUrl);let s=await this.discover(e),o=`${s.api_base.replace(/\/$/,"")}/robots/${encodeURIComponent(e)}`,i=await this._fetch(o);if(!i.ok)throw i.status===404?new k(e,s.api_base):new y(`HTTP ${i.status} from authoritative node for ${e}`,s.api_base);try{return await i.json()}catch(a){throw new y(`Invalid JSON in fallback resolve response for ${e}`,s.api_base,a instanceof Error?a:void 0)}}verifyNode(e){if(!e||typeof e!="object")return!1;let t=e;return!(typeof t.rcan_node_version!="string"||!t.rcan_node_version||typeof t.node_type!="string"||!an.has(t.node_type)||typeof t.operator!="string"||!t.operator||typeof t.namespace_prefix!="string"||!t.namespace_prefix||typeof t.public_key!="string"||!t.public_key.startsWith("ed25519:")||typeof t.api_base!="string"||!t.api_base.startsWith("https://"))}};var dn="https://rcan.dev/schemas",Te=new Map;async function fe(n){if(Te.has(n))return Te.get(n);try{let e=new AbortController,t=setTimeout(()=>e.abort(),5e3),r=await fetch(`${dn}/${n}`,{signal:e.signal});if(clearTimeout(t),!r.ok)return null;let s=await r.json();return Te.set(n,s),s}catch{return null}}async function at(n){let e=await fe("rcan-config.schema.json");if(!e)return{valid:!0,skipped:!0};let t=[];if(typeof n!="object"||n===null)return{valid:!1,errors:["Config must be an object"]};let r=n,s=e.required??[];for(let o of s)o in r||t.push(`Missing required field: ${o}`);return t.length===0?{valid:!0}:{valid:!1,errors:t}}async function ct(n){let e=await fe("rcan-node.schema.json");if(!e)return{valid:!0,skipped:!0};let t=[];if(typeof n!="object"||n===null)return{valid:!1,errors:["Manifest must be an object"]};let r=n,s=e.required??[];for(let o of s)o in r||t.push(`Missing required field: ${o}`);return t.length===0?{valid:!0}:{valid:!1,errors:t}}var Ie=(r=>(r[r.FIRE_AND_FORGET=0]="FIRE_AND_FORGET",r[r.ACKNOWLEDGED=1]="ACKNOWLEDGED",r[r.EXACTLY_ONCE=2]="EXACTLY_ONCE",r))(Ie||{}),le=class n extends Error{constructor(e){super(`ACK timeout for message ${e} \u2014 safety halt required`),this.name="QoSAckTimeoutError",Object.setPrototypeOf(this,n.prototype)}},ge=class{_send;_waitForAck;constructor(e,t){this._send=e,this._waitForAck=t}async sendWithQoS(e,t={}){let r=t.qos??0,s=t.maxRetries??3,o=t.initialBackoffMs??100,i=t.ackTimeoutMs??500;if(r===0)return await this._send(e),{delivered:!0,attempts:1,reason:"fire-and-forget"};let a=e.message_id??e.msg_id??"unknown",c=0,u=o;for(;c<=s;){if(await this._send(e),c++,await this._waitForAck(a,i))return{delivered:!0,attempts:c,reason:r===2?"exactly-once":"acknowledged"};if(c>s)break;await fn(u),u=Math.min(u*2,5e3)}return{delivered:!1,attempts:c,reason:`ACK not received after ${s} retries`}}};function dt(n,e){return{message_type:6,ruri:n,safety_event:"ESTOP",reason:e.slice(0,512),timestamp_ms:Date.now(),message_id:un(),qos:2}}function un(){if(typeof crypto<"u"&&typeof crypto.randomUUID=="function")return crypto.randomUUID();let n=Array.from({length:16},()=>Math.floor(Math.random()*256));n[6]=n[6]&15|64,n[8]=n[8]&63|128;let e=n.map(t=>t.toString(16).padStart(2,"0"));return`${e.slice(0,4).join("")}-${e.slice(4,6).join("")}-${e.slice(6,8).join("")}-${e.slice(8,10).join("")}-${e.slice(10).join("")}`}function fn(n){return new Promise(e=>setTimeout(e,n))}var Me=6;function me(){if(typeof crypto<"u"&&typeof crypto.randomUUID=="function")return crypto.randomUUID();let n=Array.from({length:16},()=>Math.floor(Math.random()*256));n[6]=n[6]&15|64,n[8]=n[8]&63|128;let e=n.map(t=>t.toString(16).padStart(2,"0"));return`${e.slice(0,4).join("")}-${e.slice(4,6).join("")}-${e.slice(6,8).join("")}-${e.slice(8,10).join("")}-${e.slice(10).join("")}`}function ut(n,e){return{message_type:6,ruri:n,safety_event:"ESTOP",reason:e.slice(0,512),timestamp_ms:Date.now(),message_id:me(),qos:2}}function ft(n,e){return{message_type:6,ruri:n,safety_event:"STOP",reason:e.slice(0,512),timestamp_ms:Date.now(),message_id:me()}}function lt(n,e){return{message_type:6,ruri:n,safety_event:"RESUME",reason:e.slice(0,512),timestamp_ms:Date.now(),message_id:me()}}function gt(n){return typeof n=="object"&&n!==null&&n.message_type===Me}function mt(n){let e=[];return n.message_type!==6&&e.push("message_type must be 6"),n.ruri||e.push("ruri is required"),["ESTOP","STOP","RESUME"].includes(n.safety_event??"")||e.push("safety_event must be ESTOP, STOP, or RESUME"),(!n.reason||n.reason.length===0)&&e.push("reason is required"),n.message_id||e.push("message_id is required"),(!n.timestamp_ms||n.timestamp_ms<=0)&&e.push("timestamp_ms must be positive"),e}function pt(n,e,t){return{message_type:11,ruri:n,disclosure:e,timestamp_ms:Date.now(),message_id:me(),delegation_chain:t}}var pe=class{windowSeconds;maxSize;_seen;constructor(e=30,t=1e4){this.windowSeconds=e,this.maxSize=t,this._seen=new Map}checkAndRecord(e,t,r=!1){let s=Date.now();this._evict(s);let o=r?Math.min(this.windowSeconds,10):this.windowSeconds,i=ln(t);if(i===null)return{allowed:!1,reason:`invalid timestamp format: ${t}`};let a=s-i,c=o*1e3;if(a>c)return{allowed:!1,reason:`message too old: age=${Math.round(a/1e3)}s > window=${o}s`};if(i>s+5e3)return{allowed:!1,reason:"message timestamp is in the future"};if(this._seen.has(e))return{allowed:!1,reason:`replay detected: msg_id ${e} already seen`};if(this._seen.size>=this.maxSize){let f=this._seen.keys().next().value;this._seen.delete(f)}let u=s+c;return this._seen.set(e,u),{allowed:!0,reason:"ok"}}_evict(e){for(let[t,r]of this._seen)r<=e&&this._seen.delete(t)}get size(){return this._seen.size}};function ht(n,e){let t=n,r=t.message_id??t.msg_id;if(!r)return{valid:!1,reason:"missing message_id / msg_id"};let s;if(typeof t.timestamp_ms=="number"?s=String(t.timestamp_ms/1e3):t.timestamp!==void 0&&(s=String(t.timestamp)),!s)return{valid:!1,reason:"missing timestamp"};let o=t.message_type===6||t.message_type===6,i=e.checkAndRecord(r,s,o);return{valid:i.allowed,reason:i.reason}}function ln(n){if(n.includes("T")||n.includes("-")){let t=new Date(n);if(!isNaN(t.getTime()))return t.getTime()}let e=parseFloat(n);return isNaN(e)?null:e>1e12?e:e*1e3}var B=class n extends Error{offsetSeconds;constructor(e,t){super(`Clock drift too large: offset=${e.toFixed(3)}s > max=${t}s`),this.name="ClockDriftError",this.offsetSeconds=e,Object.setPrototypeOf(this,n.prototype)}};async function Ue(n){let e=n??"https://worldtimeapi.org/api/ip";try{let t=Date.now(),r=await fetch(e,{method:"HEAD",signal:AbortSignal.timeout(3e3)}),s=Date.now(),o=r.headers.get("Date")??r.headers.get("date");if(!o)return{synchronized:!0,offsetSeconds:0,source:"assumed (no Date header)"};let i=new Date(o).getTime();if(isNaN(i))return{synchronized:!0,offsetSeconds:0,source:"assumed (unparseable Date header)"};let c=((t+s)/2-i)/1e3;return{synchronized:Math.abs(c)<=5,offsetSeconds:c,source:e}}catch{return{synchronized:!0,offsetSeconds:0,source:"assumed (network unavailable)"}}}async function yt(n=5){let e=await Ue();if(!e.synchronized||Math.abs(e.offsetSeconds)>n)throw new B(e.offsetSeconds,n)}async function gn(n){let e=JSON.stringify(n,Object.keys(n).sort());if(typeof crypto<"u"&&crypto.subtle){let r=new TextEncoder().encode(e),s=await crypto.subtle.digest("SHA-256",r);return Array.from(new Uint8Array(s)).map(o=>o.toString(16).padStart(2,"0")).join("")}let t=2166136261;for(let r=0;r<e.length;r++)t^=e.charCodeAt(r),t=t*16777619>>>0;return t.toString(16).padStart(8,"0")}async function Rt(n,e,t,r="rcan://local/config",s=!1){let o=await gn(n);return new l({rcan:"1.6",cmd:"CONFIG_UPDATE",target:r,params:{message_type:5,diff:n,rollback:t,scope:e,config_hash:o,safety_overrides:s}})}function St(n){let e=n.params;return!e.diff||typeof e.diff!="object"?{valid:!1,reason:"missing required field: params.diff"}:!e.config_hash||typeof e.config_hash!="string"?{valid:!1,reason:"missing required field: params.config_hash"}:"rollback"in e?e.safety_overrides===!0&&e.scope!=="creator"?{valid:!1,reason:"safety_overrides=true requires scope=creator (owner is insufficient)"}:{valid:!0,reason:"ok"}:{valid:!1,reason:"missing required field: params.rollback"}}function mn(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).slice(2)}`}var he=class{_keys=[];addKey(e){this._keys.push(e)}getJWKS(){return{keys:[...this._keys]}}findKey(e){return this._keys.find(t=>t.kid===e)}isKeyValid(e,t){let r=this.findKey(e);if(!r)return!1;let s=(t??Date.now())/1e3;return!(r.revoked_at!==void 0&&r.revoked_at<=s||r.exp!==void 0&&r.exp<s)}expireKey(e,t){let r=this.findKey(e);r&&(r.exp=t??Math.floor(Date.now()/1e3))}revokeKey(e){let t=this.findKey(e);t&&(t.revoked_at=Math.floor(Date.now()/1e3))}validKeys(e){return this._keys.filter(t=>this.isKeyValid(t.kid,e))}};function _t(n,e,t=120,r="rcan://local/keys"){let s=mn().slice(0,8);return new l({rcan:"1.6",cmd:"KEY_ROTATION",target:r,params:{message_type:5,new_public_key:n,new_kid:s,old_kid:e,overlap_seconds:t,initiated_at:new Date().toISOString()},keyId:s})}function pn(){return typeof crypto<"u"&&typeof crypto.randomUUID=="function"?crypto.randomUUID():`${Date.now()}-${Math.random().toString(36).slice(2)}`}function ye(n){let e=n.requestId??pn();return new l({rcan:"1.6",cmd:"CONSENT_REQUEST",target:n.targetRuri,params:{message_type:20,requester_ruri:n.requesterRuri,requester_owner:n.requesterOwner,target_ruri:n.targetRuri,requested_scopes:n.requestedScopes,duration_hours:n.durationHours,justification:n.justification,request_id:e,consent_type:n.consentType??"cross_robot",data_categories:n.dataCategories??[]}})}function Re(n){let e=n.expiresAt??new Date(Date.now()+864e5).toISOString();return new l({rcan:"1.6",cmd:"CONSENT_GRANT",target:"rcan://local/consent",params:{message_type:21,request_id:n.requestId,granted_scopes:n.grantedScopes??[],expires_at:e,reason:n.reason??"approved"}})}function Se(n){return new l({rcan:"1.6",cmd:"CONSENT_DENY",target:"rcan://local/consent",params:{message_type:22,request_id:n.requestId,reason:n.reason??"denied"}})}function At(n){let e=n.cmd,t=n.params,r=t.message_type;return e==="CONSENT_REQUEST"?r!==20?{valid:!1,reason:"message_type must be CONSENT_REQUEST (20)"}:t.requester_ruri?t.target_ruri?!t.requested_scopes||!Array.isArray(t.requested_scopes)||t.requested_scopes.length===0?{valid:!1,reason:"requested_scopes must be a non-empty array"}:t.request_id?t.justification?{valid:!0,reason:"ok"}:{valid:!1,reason:"missing justification"}:{valid:!1,reason:"missing request_id"}:{valid:!1,reason:"missing target_ruri"}:{valid:!1,reason:"missing requester_ruri"}:e==="CONSENT_GRANT"?r!==21?{valid:!1,reason:"message_type must be CONSENT_GRANT (21)"}:t.request_id?t.expires_at?{valid:!0,reason:"ok"}:{valid:!1,reason:"missing expires_at"}:{valid:!1,reason:"missing request_id"}:e==="CONSENT_DENY"?r!==22?{valid:!1,reason:"message_type must be CONSENT_DENY (22)"}:t.request_id?{valid:!0,reason:"ok"}:{valid:!1,reason:"missing request_id"}:{valid:!1,reason:`unknown consent command: ${e}`}}var hn=3600*1e3,K=class{_cache=new Map;get(e,t){let r=this._cache.get(e);if(!r)return;let s=t??Date.now();if(r.cachedUntil!==void 0&&r.cachedUntil<s){this._cache.delete(e);return}return r}set(e,t){let r=t??Date.now();this._cache.set(e.rrn,{...e,cachedUntil:r+hn})}invalidate(e){this._cache.delete(e)}get size(){return this._cache.size}};async function bt(n,e,t){let r=t??new K,s=r.get(n);if(s)return s;let o=`${e.replace(/\/$/,"")}/api/v1/robots/${encodeURIComponent(n)}/revocation-status`;try{let i=await fetch(o,{signal:AbortSignal.timeout(5e3)});if(!i.ok){let u={rrn:n,status:"active",reason:`registry returned ${i.status}`};return r.set(u),u}let a=await i.json(),c={rrn:n,status:a.status??"active",revokedAt:a.revokedAt,reason:a.reason,authority:a.authority};return r.set(c),c}catch{return{rrn:n,status:"active",reason:"network unavailable"}}}function vt(n,e){return new l({rcan:"1.6",cmd:"ROBOT_REVOCATION",target:"rcan://broadcast/revocation",params:{message_type:19,rrn:n,reason:e,revoked_at:new Date().toISOString()}})}var Pe=(o=>(o.VIDEO="video",o.AUDIO="audio",o.LOCATION="location",o.BIOMETRIC="biometric",o.TELEMETRY="telemetry",o))(Pe||{});function xt(n){return ye({requesterRuri:n.requesterRuri,requesterOwner:n.requesterOwner,targetRuri:n.targetRuri,requestedScopes:["training_data"],durationHours:n.durationHours,justification:n.justification,requestId:n.requestId,consentType:"training_data",dataCategories:n.dataCategories})}function Ct(n){return Re(n)}function Et(n){return Se(n)}function wt(n){if(n.params.message_type!==10)return{valid:!1,reason:"not a TRAINING_DATA message"};let e=n.params.consent_token;return!e||typeof e!="string"||e.trim()===""?{valid:!1,reason:"TRAINING_DATA message missing consent_token (\xA717)"}:{valid:!0,reason:"ok"}}var _e=class{crossOwnerGraceS;keyTtlS;_cachedKeys=[];constructor(e=3600,t=86400){this.crossOwnerGraceS=e,this.keyTtlS=t}canAcceptCommand(e,t,r,s=!0,o=!1,i,a){if(e&&e.message_type===6&&e.safety_event==="ESTOP")return{allowed:!0,reason:"ESTOP always accepted (Protocol 66)"};if(!t)return{allowed:!0,reason:"online mode"};if(!r)return{allowed:!1,reason:"offline mode: cross-network commands blocked"};if(!s)return{allowed:!1,reason:"offline mode: only owner-role commands accepted from local network"};if(o&&i!==void 0){let u=((a??Date.now())-i)/1e3;if(u>this.crossOwnerGraceS)return{allowed:!1,reason:`offline mode: cross-owner grace period expired (${Math.round(u)}s > ${this.crossOwnerGraceS}s)`}}return{allowed:!0,reason:"offline mode: owner command on local network accepted"}}cacheKey(e,t){let r=t??Date.now();this._cachedKeys=this._cachedKeys.filter(s=>s.kid!==e.kid),this._cachedKeys.push({...e,cachedAtMs:r,ttlSeconds:this.keyTtlS})}getCachedKey(e,t){let r=t??Date.now(),s=this._cachedKeys.find(i=>i.kid===e);if(!s)return;if((r-s.cachedAtMs)/1e3>s.ttlSeconds){this._cachedKeys=this._cachedKeys.filter(i=>i.kid!==e);return}return s}getManifestFields(e,t){if(e===void 0)return{offline_mode:!1,offline_since_s:0};let r=t??Date.now();return{offline_mode:!0,offline_since_s:Math.round((r-e)/1e3)}}};var De=(p=>(p.SENSOR_PROXIMITY_FAILURE="SENSOR_PROXIMITY_FAILURE",p.SENSOR_CAMERA_FAILURE="SENSOR_CAMERA_FAILURE",p.SENSOR_IMU_FAILURE="SENSOR_IMU_FAILURE",p.MOTOR_OVERCURRENT="MOTOR_OVERCURRENT",p.MOTOR_OVERTEMP="MOTOR_OVERTEMP",p.MOTOR_STALL="MOTOR_STALL",p.BATTERY_CRITICAL="BATTERY_CRITICAL",p.BATTERY_LOW="BATTERY_LOW",p.NETWORK_TIMEOUT="NETWORK_TIMEOUT",p.NETWORK_REGISTRY_UNREACHABLE="NETWORK_REGISTRY_UNREACHABLE",p.SAFETY_ESTOP_STUCK="SAFETY_ESTOP_STUCK",p.SAFETY_WATCHDOG_TIMEOUT="SAFETY_WATCHDOG_TIMEOUT",p.UNKNOWN="UNKNOWN",p))(De||{});function Nt(n){return new l({rcan:"1.6",cmd:"FAULT_REPORT",target:n.target??"rcan://local/fault",params:{message_type:26,fault_code:n.faultCode,severity:n.severity,subsystem:n.subsystem,affects_safety:n.affectsSafety,safe_to_continue:n.safeToContinue,description:n.description??"",reported_at:new Date().toISOString()}})}var Ae=(r=>(r[r.ANONYMOUS=1]="ANONYMOUS",r[r.EMAIL_VERIFIED=2]="EMAIL_VERIFIED",r[r.HARDWARE_TOKEN=3]="HARDWARE_TOKEN",r))(Ae||{}),Le={minLoaDiscover:1,minLoaStatus:1,minLoaChat:1,minLoaControl:1,minLoaSafety:1},Ot={minLoaDiscover:1,minLoaStatus:1,minLoaChat:1,minLoaControl:2,minLoaSafety:3};function be(n){try{let e=n.split(".");if(e.length<2)return 1;let t=(e[1]??"").replace(/-/g,"+").replace(/_/g,"/"),r=t+"=".repeat((4-t.length%4)%4),s;typeof atob<"u"?s=atob(r):s=Buffer.from(r,"base64").toString("utf-8");let i=JSON.parse(s).loa;if(typeof i=="number"&&i>=1&&i<=3)return i}catch{}return 1}function yn(n,e){switch(n.toLowerCase()){case"discover":return e.minLoaDiscover;case"status":return e.minLoaStatus;case"chat":return e.minLoaChat;case"control":return e.minLoaControl;case"safety":return e.minLoaSafety;default:return null}}function kt(n,e,t=Le){let r=yn(e,t);return r===null?{valid:!0,reason:"unknown scope; allowed by default"}:n>=r?{valid:!0,reason:"ok"}:{valid:!1,reason:`LOA_INSUFFICIENT: scope=${e} requires LoA>=${r}, caller has LoA=${n}`}}var $e=(r=>(r.ROOT="root",r.AUTHORITATIVE="authoritative",r.COMMUNITY="community",r))($e||{}),je=(r=>(r.CONSENT="consent",r.REVOCATION="revocation",r.KEY="key",r))(je||{}),Rn=1440*60*1e3,ve=class{store=new Map;set(e){this.store.set(e.registryUrl,{identity:e,expiresAt:Date.now()+Rn})}lookup(e){let t=this.store.get(e);if(t){if(Date.now()>t.expiresAt){this.store.delete(e);return}return t.identity}}async discoverViaDns(e){let t=`_rcan-registry.${e}`,r;try{r=await ze("dns").promises.resolveTxt(t)}catch{return}for(let s of r){let o=s.join("");try{let i=JSON.parse(o);if(i.registryUrl&&i.tier&&i.publicKeyPem&&i.domain){let a={registryUrl:i.registryUrl,tier:i.tier,publicKeyPem:i.publicKeyPem,domain:i.domain,verifiedAt:new Date().toISOString()};return this.set(a),a}}catch{}}}async verifyRegistryJwt(e,t){let r=this.lookup(t);if(!r)throw new Error(`REGISTRY_UNKNOWN: ${t} is not in the trust cache`);let s;try{let i=(e.split(".")[1]??"").replace(/-/g,"+").replace(/_/g,"/"),a=i+"=".repeat((4-i.length%4)%4),c;typeof atob<"u"?c=atob(a):c=Buffer.from(a,"base64").toString("utf-8");let u=JSON.parse(c);s=typeof u.iss=="string"?u.iss:void 0}catch{throw new Error("REGISTRY_JWT_MALFORMED: cannot decode token payload")}if(s!==t)throw new Error(`REGISTRY_JWT_ISS_MISMATCH: expected iss=${t}, got iss=${s??"(none)"}`);return r}};function Sn(){if(typeof crypto<"u"&&typeof crypto.randomUUID=="function")return crypto.randomUUID();let n=Array.from({length:16},()=>Math.floor(Math.random()*256));n[6]=(n[6]??0)&15|64,n[8]=(n[8]??0)&63|128;let e=n.map(t=>t.toString(16).padStart(2,"0"));return`${e.slice(0,4).join("")}-${e.slice(4,6).join("")}-${e.slice(6,8).join("")}-${e.slice(8,10).join("")}-${e.slice(10).join("")}`}function Tt(n,e,t,r){return new l({rcan:"1.6",rcanVersion:"1.6",cmd:"federation_sync",target:e,params:{msg_type:12,msg_id:Sn(),source_registry:n,target_registry:e,sync_type:t,payload:r},timestamp:new Date().toISOString()})}async function It(n,e,t){let r=n.params?.msg_type;if(r===6||r===6||n.cmd==="estop"||n.cmd==="ESTOP")return{valid:!0,reason:"ESTOP always permitted (P66 invariant)"};let o=n.params?.source_registry??n.params?.from_registry;if(!o||o===e)return{valid:!0,reason:"local registry; no federation check needed"};if(!t.lookup(o))return{valid:!1,reason:`REGISTRY_UNKNOWN: ${o} is not in the local trust cache`};let a=1,c=n.params?.registry_jwt;return c?a=be(c):typeof n.loa=="number"&&(a=n.loa),a<2?{valid:!1,reason:`LOA_INSUFFICIENT: cross-registry commands require LoA>=2 (EMAIL_VERIFIED), got LoA=${a}`}:{valid:!0,reason:"cross-registry command accepted"}}var x=class n extends Error{constructor(e){super(e),this.name="TransportError",Object.setPrototypeOf(this,n.prototype)}},He=(s=>(s.HTTP="http",s.COMPACT="compact",s.MINIMAL="minimal",s.BLE="ble",s))(He||{}),qe={msg_type:"t",msg_id:"i",timestamp:"ts",from_rrn:"f",to_rrn:"to",scope:"s",payload:"p",signature:"sig"},Mt=Object.fromEntries(Object.entries(qe).map(([n,e])=>[e,n]));function Be(n){let e=n.toJSON(),t={};for(let[o,i]of Object.entries(e)){let a=qe[o];t[a??o]=i}if(t.p&&typeof t.p=="object"){let o=t.p,i={};for(let[a,c]of Object.entries(o)){let u=qe[a];i[u??a]=c}t.p=i}let r=JSON.stringify(t);return new TextEncoder().encode(r)}function Ke(n){let t=new TextDecoder().decode(n),r=JSON.parse(t),s={};for(let[o,i]of Object.entries(r)){let a=Mt[o];s[a??o]=i}if(s.payload&&typeof s.payload=="object"){let o=s.payload,i={};for(let[a,c]of Object.entries(o)){let u=Mt[a];i[u??a]=c}s.payload=i}return new l({rcan:s.rcan??"1.6",rcanVersion:s.rcanVersion,cmd:s.cmd,target:s.target,params:s.params??s.payload??{},timestamp:s.timestamp,confidence:s.confidence,signature:s.signature})}var Y=32,Fe=6;async function Ut(n){let e=new TextEncoder().encode(n),t=new ArrayBuffer(e.byteLength);new Uint8Array(t).set(e);let r=await crypto.subtle.digest("SHA-256",t);return new Uint8Array(r)}async function Pt(n){let e=n.params?.msg_type??0;if(e!==Fe)throw new x(`encodeMinimal only supports SAFETY (type 6) messages; got type=${e}`);let t=n.params?.from_rrn??n.target??"",r=n.params?.to_rrn??n.target??"",s=await Ut(t),o=await Ut(r),i=(n.signature?.sig??"").replace(/[^A-Za-z0-9+/=]/g,""),a;try{if(typeof atob<"u"){let N=atob(i.slice(0,16));a=new Uint8Array(N.length);for(let h=0;h<N.length;h++)a[h]=N.charCodeAt(h)}else a=Buffer.from(i.slice(0,16),"base64")}catch{a=new Uint8Array(8)}let u=(n.timestamp?Math.floor(new Date(n.timestamp).getTime()/1e3):Math.floor(Date.now()/1e3))>>>0,f=new Uint8Array(Y),q=new DataView(f.buffer);q.setUint16(0,Fe,!1),f.set(s.subarray(0,8),2),f.set(o.subarray(0,8),10),q.setUint32(18,u,!1);let A=new Uint8Array(8);A.set(a.subarray(0,Math.min(8,a.length))),f.set(A,22);let p=0;for(let N=0;N<30;N++)p^=f[N]??0;if(q.setUint16(30,p&65535,!1),f.length!==Y)throw new x(`encodeMinimal assertion failed: expected ${Y} bytes, got ${f.length}`);return f}function Dt(n){if(n.length!==Y)throw new x(`decodeMinimal: expected ${Y} bytes, got ${n.length}`);let e=new DataView(n.buffer,n.byteOffset,n.byteLength),t=e.getUint16(0,!1),r=n.subarray(2,10),s=n.subarray(10,18),o=e.getUint32(18,!1),i=n.subarray(22,30),a=new Date(o*1e3).toISOString(),c=u=>Array.from(u).map(f=>f.toString(16).padStart(2,"0")).join("");return{params:{msg_type:t,from_hash:c(r),to_hash:c(s),timestamp_s:o,sig_truncated:c(i)},timestamp:a}}var _n=251,V=3;function Lt(n,e=_n){let t=Be(n),r=e-V;if(r<=0)throw new x(`MTU ${e} is too small (need at least ${V+1})`);let s=Math.ceil(t.length/r),o=[];for(let i=0;i<s;i++){let a=t.subarray(i*r,(i+1)*r),c=new Uint8Array(V+a.length);c[0]=i,c[1]=s,c[2]=i===s-1?1:0,c.set(a,V),o.push(c)}return o}function $t(n){if(n.length===0)throw new x("decodeBleFrames: no frames provided");let e=[...n].sort((a,c)=>(a[0]??0)-(c[0]??0)),t=e[0]?.[1]??e.length;if(e.length!==t)throw new x(`decodeBleFrames: expected ${t} frames, got ${e.length}`);let r=e.map(a=>a.subarray(V)),s=r.reduce((a,c)=>a+c.length,0),o=new Uint8Array(s),i=0;for(let a of r)o.set(a,i),i+=a.length;return Ke(o)}function jt(n,e){let r=(e.params?.msg_type??0)===Fe,s=o=>n.includes(o);if(r){if(s("minimal"))return"minimal";if(s("ble"))return"ble";if(s("compact"))return"compact";if(s("http"))return"http"}else{if(s("http"))return"http";if(s("compact"))return"compact";if(s("ble"))return"ble"}throw new x(`No suitable transport available from: [${n.join(", ")}]`)}var Ve=(t=>(t.BASE64="base64",t.REF="ref",t))(Ve||{});function J(){if(typeof crypto<"u"&&typeof crypto.randomUUID=="function")return crypto.randomUUID();let n=Array.from({length:16},()=>Math.floor(Math.random()*256));n[6]=(n[6]??0)&15|64,n[8]=(n[8]??0)&63|128;let e=n.map(t=>t.toString(16).padStart(2,"0"));return`${e.slice(0,4).join("")}-${e.slice(4,6).join("")}-${e.slice(6,8).join("")}-${e.slice(8,10).join("")}-${e.slice(10).join("")}`}async function Ye(n){let e=new ArrayBuffer(n.byteLength);new Uint8Array(e).set(n);let t=await crypto.subtle.digest("SHA-256",e),r=new Uint8Array(t);return Array.from(r).map(s=>s.toString(16).padStart(2,"0")).join("")}function qt(n){if(typeof Buffer<"u")return Buffer.from(n).toString("base64");let e="";for(let t=0;t<n.length;t++)e+=String.fromCharCode(n[t]??0);return btoa(e)}function Je(n,e){let t={...n.toJSON(),...e};return l.fromJSON(t)}async function Ge(n,e,t){let r=await Ye(e),s=qt(e),o={chunkId:J(),mimeType:t,encoding:"base64",hashSha256:r,dataB64:s,sizeBytes:e.length},i=n.mediaChunks??[];return Je(n,{mediaChunks:[...i,o]})}function Ft(n,e,t,r,s){let o={chunkId:J(),mimeType:t,encoding:"ref",hashSha256:r,refUrl:e,sizeBytes:s},i=n.mediaChunks??[];return Je(n,{mediaChunks:[...i,o]})}async function Ht(n){let e=n.mediaChunks??[];if(e.length===0)return{valid:!0,reason:"no media chunks"};for(let t=0;t<e.length;t++){let r=e[t];if(!r.chunkId)return{valid:!1,reason:`chunk[${t}]: missing chunkId`};if(!r.mimeType)return{valid:!1,reason:`chunk[${t}]: missing mimeType`};if(!r.hashSha256)return{valid:!1,reason:`chunk[${t}]: missing hashSha256`};if(r.sizeBytes<0)return{valid:!1,reason:`chunk[${t}]: sizeBytes must be >= 0`};if(r.encoding==="base64"){if(!r.dataB64)return{valid:!1,reason:`chunk[${t}]: BASE64 encoding requires dataB64`};let s;try{if(typeof Buffer<"u")s=Buffer.from(r.dataB64,"base64");else{let i=atob(r.dataB64);s=new Uint8Array(i.length);for(let a=0;a<i.length;a++)s[a]=i.charCodeAt(a)}}catch{return{valid:!1,reason:`chunk[${t}]: failed to decode base64 data`}}let o=await Ye(s);if(o!==r.hashSha256)return{valid:!1,reason:`chunk[${t}]: SHA-256 mismatch (expected ${r.hashSha256}, got ${o})`}}else if(r.encoding==="ref"){if(!r.refUrl)return{valid:!1,reason:`chunk[${t}]: REF encoding requires refUrl`}}else return{valid:!1,reason:`chunk[${t}]: unknown encoding '${r.encoding}'`}}return{valid:!0,reason:"ok"}}async function Bt(n){let e=new l({rcan:"1.6",rcanVersion:"1.6",cmd:"training_data",target:"rcan://training/data",params:{msg_type:10,msg_id:J()},timestamp:new Date().toISOString()});for(let t of n)e=await Ge(e,t.data,t.mimeType);return e}async function Kt(n,e,t,r,s){let o=await Ye(e),i=qt(e),a={chunkId:J(),mimeType:t,encoding:"base64",hashSha256:o,dataB64:i,sizeBytes:e.length},c={streamId:n,chunkIndex:r,isFinal:s,chunk:a},u=new l({rcan:"1.6",rcanVersion:"1.6",cmd:"stream_chunk",target:"rcan://streaming/chunk",params:{msg_type:7,msg_id:J(),stream_chunk:c},timestamp:new Date().toISOString()});return u=Je(u,{mediaChunks:[a]}),u}var An="0.6.0",bn="1.6";return Zt(vn);})();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@continuonai/rcan-ts",
3
- "version": "0.5.0",
4
- "description": "Official TypeScript SDK for the RCAN v1.5 robot communication protocol",
3
+ "version": "0.6.0",
4
+ "description": "Official TypeScript SDK for the RCAN v1.6 robot communication protocol",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",