openrtc 2.3.1 → 2.5.1
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.
- package/README.md +77 -5
- package/dist/BrowserManagedBroadcastHost-ARCP5MGJ.js +1 -0
- package/dist/{ITransport-CjxCQ6q7.d.ts → Connection-CTpuImO-.d.ts} +610 -95
- package/dist/DelegatingRuntimeAdapter-D67Ozqo3.d.ts +154 -0
- package/dist/IpcRuntimeAdapter-Ddx0MtSI.d.ts +86 -0
- package/dist/WasmBridge-ZXBCXBBM.js +1 -0
- package/dist/{assembly-Bmi65-tK.d.ts → assembly-DvfsYFCL.d.ts} +41 -19
- package/dist/{capabilities-BPuynml5.d.ts → capabilities-CmzzxSvW.d.ts} +14 -7
- package/dist/chunk-2GX6GB6L.js +1 -0
- package/dist/chunk-2K47N3QP.js +2 -0
- package/dist/chunk-72NEEJQG.js +1 -0
- package/dist/chunk-AYHD4X2R.js +1 -0
- package/dist/chunk-BFN3AVHA.js +2 -0
- package/dist/chunk-BGWJHPBC.js +2 -0
- package/dist/chunk-CCCYE3XN.js +1 -0
- package/dist/chunk-EIJNERKZ.js +1 -0
- package/dist/chunk-FEF3DPPB.js +1 -0
- package/dist/chunk-GHAJW6SZ.js +2 -0
- package/dist/chunk-GTHSRQ7Y.js +2 -0
- package/dist/chunk-JPBW67B3.js +1 -0
- package/dist/chunk-LLZT3MR6.js +118 -0
- package/dist/chunk-N6LGTNUI.js +1 -0
- package/dist/{chunk-4MLJXEVV.js → chunk-NDR2ANQB.js} +1 -1
- package/dist/chunk-OT7IPLZE.js +1 -0
- package/dist/chunk-OWKAJPOI.js +1 -0
- package/dist/chunk-TYZS5LXQ.js +2 -0
- package/dist/chunk-VFDCIEP6.js +2 -0
- package/dist/chunk-VTYVIKTM.js +1 -0
- package/dist/chunk-XTYALGJN.js +2 -0
- package/dist/{chunk-KRJECX7X.js → chunk-Z4KJHIV5.js} +1 -1
- package/dist/chunk-Z54XUIKZ.js +1 -0
- package/dist/{controlPlane-KVFZ7BR5.js → controlPlane-IIPEJ77Q.js} +1 -1
- package/dist/coreClient.d.ts +3 -4
- package/dist/coreClient.js +1 -1
- package/dist/{deviceEnrollment-VACC64CQ.js → deviceEnrollment-ZQZ2WP5H.js} +2 -2
- package/dist/{deviceKey-Y35WSEQQ.js → deviceKey-EIMDBAQS.js} +1 -1
- package/dist/{dist-FIVA6EPA.js → dist-XO466BRG.js} +18 -0
- package/dist/index.d.ts +7 -7
- package/dist/index.js +1 -1
- package/dist/{ipc-CPnNwv6f.d.ts → ipc-DgzKqHH3.d.ts} +3 -0
- package/dist/ipcFactory-PRAJ7JP7.js +1 -0
- package/dist/native.d.ts +21 -0
- package/dist/native.js +1 -0
- package/dist/node-browser.d.ts +8 -0
- package/dist/node-browser.js +1 -0
- package/dist/node.d.ts +87 -0
- package/dist/node.js +2 -0
- package/dist/openrtc-VCS6V3AN.js +2 -0
- package/dist/openrtc_bg.wasm +0 -0
- package/dist/protocol-BSBjMb7p.d.ts +6 -0
- package/dist/room-ULZ2FGWV.js +1 -0
- package/dist/runtime/WasmRuntimeAdapter.d.ts +4 -5
- package/dist/runtime/WasmRuntimeAdapter.js +1 -1
- package/dist/runtime/device-status.d.ts +1 -2
- package/dist/runtime/factories.d.ts +352 -8
- package/dist/runtime/factories.js +1 -1
- package/dist/runtime/index.d.ts +15 -161
- package/dist/runtime/index.js +1 -1
- package/dist/server-browser.d.ts +14 -0
- package/dist/server-browser.js +1 -0
- package/dist/server.d.ts +44 -0
- package/dist/server.js +2 -0
- package/dist/service-node.d.ts +155 -0
- package/dist/service-node.js +1 -0
- package/dist/testing/native.d.ts +11 -0
- package/dist/testing/native.js +1 -0
- package/dist/testing.d.ts +47 -20
- package/dist/testing.js +1 -1
- package/dist/transport/index.d.ts +7 -18
- package/dist/transport/index.js +1 -1
- package/dist/types-Cyc-mPjk.d.ts +650 -0
- package/package.json +35 -3
- package/dist/DelegatingRuntimeAdapter-DE4LTGAJ.d.ts +0 -399
- package/dist/IpcRuntimeAdapter-CE0va9Tr.d.ts +0 -19
- package/dist/WasmBridge-75F6GKHG.js +0 -1
- package/dist/chunk-2L6ULC32.js +0 -1
- package/dist/chunk-2SUSPEC4.js +0 -1
- package/dist/chunk-7BJKDBLP.js +0 -2
- package/dist/chunk-AJQVMVYW.js +0 -1
- package/dist/chunk-BOS554IK.js +0 -2
- package/dist/chunk-HEAJ7ZUR.js +0 -1
- package/dist/chunk-HUG5AX7R.js +0 -1
- package/dist/chunk-Q6KXVTSH.js +0 -2
- package/dist/chunk-R35AWMNY.js +0 -1
- package/dist/chunk-UILOGUOU.js +0 -1
- package/dist/chunk-WA434EWD.js +0 -2
- package/dist/chunk-XAL4T6TB.js +0 -3
- package/dist/chunk-Z2IS6NH2.js +0 -2
- package/dist/ipcFactory-32R47AVK.js +0 -1
- package/dist/openrtc-MWLNTJI7.js +0 -2
- package/dist/types--jQzenZR.d.ts +0 -295
- package/dist/types-DDhMQkK8.d.ts +0 -621
package/README.md
CHANGED
|
@@ -100,6 +100,75 @@ const team = await rtc.rooms.join('team', {
|
|
|
100
100
|
Every long-lived capability has `close()`; spaces and rooms also have
|
|
101
101
|
`leave()`. One handle activates exactly one avenue.
|
|
102
102
|
|
|
103
|
+
## Developer service nodes
|
|
104
|
+
|
|
105
|
+
`openrtc/service-node` exposes a preview WebSocket-server-like application
|
|
106
|
+
surface for browser/WASM. Browser code supplies a callback
|
|
107
|
+
that obtains a short-lived authority grant from the developer backend; it must
|
|
108
|
+
never receive a developer `sk_*` key. Trusted Node/server code can mint that
|
|
109
|
+
grant with `openrtc/server`.
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { ServiceNode } from 'openrtc/service-node';
|
|
113
|
+
|
|
114
|
+
const service = new ServiceNode({
|
|
115
|
+
client: rtc,
|
|
116
|
+
apiKey,
|
|
117
|
+
serviceId: 'world-simulation',
|
|
118
|
+
generation: 1,
|
|
119
|
+
shardIds: ['zone-a'],
|
|
120
|
+
deviceId: await rtc.devices.localId(),
|
|
121
|
+
deviceSigner,
|
|
122
|
+
assignmentSigner,
|
|
123
|
+
grantIssuer: (request) => fetch('/api/openrtc/authority-grant', {
|
|
124
|
+
method: 'POST',
|
|
125
|
+
body: JSON.stringify(request),
|
|
126
|
+
}).then((response) => response.json()),
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
service.onConnection(({ connection }) => console.log(connection.id));
|
|
130
|
+
await service.listen('world-42');
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Trusted Node.js authorities use the dedicated Rust host through `openrtc/node`;
|
|
134
|
+
no application IPC bridge or native addon is required:
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
import { ServiceNode } from 'openrtc/node';
|
|
138
|
+
|
|
139
|
+
const service = new ServiceNode({
|
|
140
|
+
apiKey: process.env.OPENRTC_API_KEY!,
|
|
141
|
+
secretKey: process.env.OPENRTC_SECRET_KEY!,
|
|
142
|
+
serviceId: 'world-simulation',
|
|
143
|
+
generation: 1,
|
|
144
|
+
shardIds: ['zone-a'],
|
|
145
|
+
deviceId: 'world-simulation-1',
|
|
146
|
+
stateDirectory: '/var/lib/world-simulation/openrtc', // private and persistent
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
service.onConnection(({ connection }) => {
|
|
150
|
+
connection.onMessage((message) => console.log(connection.peerId, message));
|
|
151
|
+
});
|
|
152
|
+
await service.listen('world-42');
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The released package must contain the signed native artifact for the current
|
|
156
|
+
`process.platform`/`process.arch`; a missing artifact fails closed. A reviewed
|
|
157
|
+
source checkout can instead opt into `buildFromSource: true` with an absolute
|
|
158
|
+
`sourceRoot`. The developer secret is sent only over the child's stdin, and
|
|
159
|
+
the Node layer only demultiplexes bounded application messages and authority
|
|
160
|
+
assignments. The Rust peer-session actor remains the sole lifecycle owner.
|
|
161
|
+
This preview Node facade intentionally owns one room and exposes only
|
|
162
|
+
message-oriented `send`/`onMessage`/`onClose` plus assignment publication; it
|
|
163
|
+
does not yet claim the browser facade's streams, media, or full Room
|
|
164
|
+
namespaces. Browser resolution of `openrtc/node` fails closed; browser code
|
|
165
|
+
uses WASM plus delegated grants through `openrtc/service-node`. Native Rust
|
|
166
|
+
uses `ControlPlane::join_authority_room` directly and does not require
|
|
167
|
+
JavaScript.
|
|
168
|
+
|
|
169
|
+
The authority surface remains preview-only until signed prebuilt artifacts and
|
|
170
|
+
source-bound browser, Node, and native Rust authority E2E lanes pass.
|
|
171
|
+
|
|
103
172
|
## Optional trust adapters
|
|
104
173
|
|
|
105
174
|
Attestation is evaluated at device enrollment, key rotation, recovery, or risk
|
|
@@ -166,8 +235,11 @@ overrides live only in `openrtc/testing`.
|
|
|
166
235
|
|
|
167
236
|
Relay, durable membership, managed attestation, MoQ, and BLE require both
|
|
168
237
|
portal enablement and explicit runtime opt-in. Avenues default to 8 peers.
|
|
169
|
-
Reviewed non-room avenues may request 9-12 peers.
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
238
|
+
Reviewed non-room avenues may request 9-12 peers. Rooms default to
|
|
239
|
+
`architecture: 'auto'` and `payload: 'reliable'`. Small rooms use a direct
|
|
240
|
+
mesh. A room may declare `payload: 'latest-state'` so auto can use the reviewed
|
|
241
|
+
four-neighbor sparse graph through 50 members. Reliable rooms above the safe
|
|
242
|
+
mesh limit require
|
|
243
|
+
the explicitly enabled, content-blind managed path. `advancedFanout: true` is a
|
|
244
|
+
one-release alias for fixed sparse latest-state delivery. `state()` remains
|
|
245
|
+
unavailable in sparse rooms; use a named channel with application revisions.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import {b,a as a$2}from'./chunk-BGWJHPBC.js';import {a}from'./chunk-AYHD4X2R.js';import {b as b$1,a as a$1}from'./chunk-LLZT3MR6.js';import'./chunk-JPBW67B3.js';var y=class{constructor(e){this.deps=e;this.active=null;this.commands=Promise.resolve();}apply(e){let t=this.commands.then(()=>this.applyOrdered(e));return this.commands=t.catch(()=>{}),t}dispose(){this.retire();}async applyOrdered(e){if(e.type==="open"){await this.open(e);return}if(this.isCurrent(e)){if(e.type==="publish"){if(!this.active||!["owner","publisher","processor"].includes(this.active.role))throw new Error("broadcast role cannot publish");let t=await this.duplex(e.sourceSlot,true),r=this.active.writers.get(e.sourceSlot);r||(r=t.writable.getWriter(),this.active.writers.set(e.sourceSlot,r)),await b(r.write(e.object),2e3,"broadcast object write");return}if(e.type==="subscribe"){if(!this.active||!["owner","subscriber","processor"].includes(this.active.role))throw new Error("broadcast role cannot subscribe");await Promise.all(e.sourceSlots.map(async t=>{let r=await this.duplex(t,false),a=this.active;this.readObjects(a,t,r.readable).catch(async()=>{if(!(this.active!==a||a.closed))try{await this.deps.observe({type:"failed",broadcastGeneration:a.broadcastGeneration,grantGeneration:a.grantGeneration,retryable:!1,code:"relay-object-rejected"});}catch{}});}));return}this.retire(),await this.deps.observe({type:"closed",broadcastGeneration:e.broadcastGeneration,grantGeneration:e.grantGeneration,code:e.reason});}}async open(e){this.retire();try{let t=this.deps.openSession?await this.deps.openSession(e.relay.relayUrl,e.relay.token):await A(e.relay.relayUrl,e.relay.token),r={broadcastGeneration:e.broadcastGeneration,grantGeneration:e.grantGeneration,role:e.role,namespace:e.relay.namespace,session:t,duplexes:new Map,writers:new Map,closed:!1};if(this.active=r,t.onClose(()=>{this.active!==r||r.closed||this.deps.observe({type:"failed",broadcastGeneration:r.broadcastGeneration,grantGeneration:r.grantGeneration,retryable:!0,code:"relay-session-closed"});}),await b(t.init(),1e4,"broadcast MoQ Draft 14 setup"),await b(t.waitForSetup(),5e3,"broadcast MoQ Draft 14 setup"),this.active!==r)return;await this.deps.observe({type:"opened",broadcastGeneration:r.broadcastGeneration,grantGeneration:r.grantGeneration});}catch{this.matches(e)&&(this.retire(),await this.deps.observe({type:"failed",broadcastGeneration:e.broadcastGeneration,grantGeneration:e.grantGeneration,retryable:true,code:"relay-open-failed"}));}}async duplex(e,t){let r=this.active;if(!r)throw new Error("broadcast session is unavailable");let a=`${t?"pub":"sub"}:${e}`,o=r.duplexes.get(a);if(o)return o;let n=`${r.namespace}/source/${e}`,l=`${r.namespace}/control/${r.grantGeneration}/${e}`,c=await b(r.session.openObjectStreamDuplex(t?n:l,t?l:n,"openrtc-broadcast-1"),12e3,"broadcast MoQ Draft 14 object stream");if(this.active!==r)throw c.close(),new Error("broadcast generation retired during setup");return r.duplexes.set(a,c),c}async readObjects(e,t,r){let a=r.getReader();try{for(;this.active===e;){let o=await a.read();if(o.done)break;await this.deps.onObject({broadcastGeneration:e.broadcastGeneration,grantGeneration:e.grantGeneration,sourceSlot:t,object:o.value})&&await this.deps.observe({type:"usage",broadcastGeneration:e.broadcastGeneration,grantGeneration:e.grantGeneration,deliveredBytes:o.value.byteLength});}}finally{a.releaseLock();}}isCurrent(e){return this.matches(e)&&this.active?.closed===false}matches(e){return this.active?.broadcastGeneration===e.broadcastGeneration&&this.active.grantGeneration===e.grantGeneration}retire(){let e=this.active;if(this.active=null,!!e){e.closed=true;for(let t of e.writers.values())try{t.releaseLock();}catch{}for(let t of e.duplexes.values())try{t.close();}catch{}e.session.close();}}};async function A(m,e){let t=new URL(m);if(t.protocol!=="https:"||t.search||t.hash||!/^[A-Za-z0-9._-]{16,16384}$/.test(e))throw new Error("broadcast relay access is invalid");let r=new URL(t.toString());r.pathname=`${r.pathname.replace(/\/+$/,"")}/${encodeURIComponent(e)}`;let a=new WebTransport(r.toString());return await b(a.ready,15e3,"broadcast relay connection"),new a$2(a,t)}var g=class{constructor(e,t,r,a,o){this.wasm=e;this.handleId=t;this.drain=o;this.incoming=null;this.incomingWriters=new Map;this.sources=new Map;this.closed=false;let n=a[0]??"",l={beginOpenRtcMediaPublication:async s=>{let d=this.wasm.__beginOpenRtcBroadcastPublication(this.handleId,n,s.publicationId||void 0,s.kind,s.codec,s.clockRate,s.codedWidth,s.codedHeight,s.channels);return await this.drain(),{...d,control:new Uint8Array(d.control??[])}},encodeOpenRtcMediaSample:async s=>(this.wasm.__publishOpenRtcBroadcastSample(this.handleId,s.publicationId,s.timestampUs,s.durationUs,s.keyframe,s.discardable,s.payload),await this.drain(),new Uint8Array),pauseOpenRtcMediaPublication:async s=>{this.wasm.__pauseOpenRtcBroadcastPublication(this.handleId,s);},retireOpenRtcMediaPublication:async s=>{this.wasm.__retireOpenRtcBroadcastPublication(this.handleId,s);},retireOpenRtcMediaReceiver:async(s,d)=>{this.wasm.__retireOpenRtcMediaReceiver(s,d);},decodeOpenRtcMediaControl:async s=>this.wasm.__decodeOpenRtcMediaControl(s),decodeOpenRtcMediaChunk:async s=>{let d=this.wasm.__decodeOpenRtcMediaChunk(s);return {...d,payload:new Uint8Array(d.payload)}}},c={createBidirectionalStream:async()=>({protocol:"openrtc-media/1",readable:new ReadableStream({start(s){s.close();}}),writable:new WritableStream})};if(this.media=new b$1(c,l,(s,d)=>(this.incoming=d,()=>{this.incoming=null;})),["owner","publisher","processor"].includes(r)&&!n)throw new Error("[OpenRTC] Broadcast publisher grant has no source slot.")}addTrack(e,t){return this.media.addTrack(e,t)}removeTrack(e){return this.media.removeTrack(e)}onTrack(e){return this.media.onTrack(t=>e({...t,source:{id:this.sources.get(t.receiver.id)??"unknown"}}))}senders(){return this.media.senders()}receivers(){return this.media.receivers()}async accept(e,t){if(this.closed)return false;let r=this.wasm.__acceptOpenRtcBroadcastObject(this.handleId,e,t);if(!r)return false;let a=r.publicationId;if(this.sources.set(a,r.sourceSlot),r.control){let n=this.incomingWriters.get(a);if(r.controlType==="stop")return n?.generation===r.mediaGeneration&&(this.incomingWriters.delete(a),await n.writer.close().catch(()=>{})),this.sources.delete(a),true;if(r.controlType!=="publish"||n&&n.generation>=r.mediaGeneration)return true;n&&await n.writer.close().catch(()=>{});let l=new TransformStream,c=l.writable.getWriter();return this.incomingWriters.set(a,{generation:r.mediaGeneration,writer:c}),this.incoming?.({peerId:r.sourceSlot,protocol:"openrtc-media/1",readable:l.readable,writable:new WritableStream}),await c.write(a$1(new Uint8Array(r.control))),true}if(!r.media)return true;let o=this.incomingWriters.get(a);return !o||o.generation!==r.mediaGeneration||await o.writer.write(a$1(new Uint8Array(r.media))),true}async close(){this.closed||(this.closed=true,await Promise.all([...this.incomingWriters.values()].map(({writer:e})=>e.close().catch(()=>{}))),this.incomingWriters.clear(),this.sources.clear(),await this.media.close());}};var M=class{constructor(e){this.deps=e;this.wasmPromise=null;this.sessions=new Set;this.publishers=new Set;}async open(e){return this.openResolved(e)}async create(e){let t=e.auth??this.deps.defaultAuth;if(!t||!this.deps.manage||!this.deps.deviceId)throw new Error("Managed broadcast creation requires authenticated control-plane access.");let r=await this.deps.manage({action:"create",deviceId:await this.deps.deviceId(),auth:t,create:e});if(!r)throw new Error("Managed broadcast creation returned no grant.");return r}async renew(e,t){let r=await this.manageGrant("renew",e,t);if(!r)throw new Error("Managed broadcast renewal returned no grant.");return r}async invite(e,t,r){let a=await this.manage("invite",r,{grant:e,invitation:t});if(!a)throw new Error("Managed broadcast invitation returned no token.");return a}async accept(e,t){let r=await this.manage("accept",t,{invite:e});if(!r)throw new Error("Managed broadcast invitation acceptance returned no grant.");return r}async revoke(e,t,r){await this.manage("revoke",r,{grant:e,invite:t});}async leave(e,t){await this.manageGrant("leave",e,t);}async closeGrant(e,t){await this.manageGrant("close",e,t);}async preparePublisher(){let e=await this.wasm(),t=a.create(e);this.publishers.add(t);let r=false;return {verificationKey:t.verificationKey.slice(),open:a=>{if(r)throw new Error("broadcast publisher signer is closed");return this.openResolved(a,t)},close:async()=>{r||(r=true,t.close(),this.publishers.delete(t));}}}async close(){await Promise.all([...this.sessions].map(e=>e.close()));for(let e of this.publishers)e.close();this.publishers.clear();}wasm(){return this.wasmPromise??(this.wasmPromise=this.deps.loadWasm())}async manageGrant(e,t,r){return this.manage(e,r,{grant:t})}async manage(e,t,r){let a=t??this.deps.defaultAuth;if(!a||!this.deps.manage||!this.deps.deviceId)throw new Error(`Managed broadcast ${e} requires authenticated control-plane access.`);return this.deps.manage({action:e,deviceId:await this.deps.deviceId(),auth:a,...r})}async openResolved(e,t){let[r,a]=await Promise.all([this.wasm(),this.deps.resolve(e,t?.verificationKey)]),o=Date.now(),n;if(t)n=await t.open(a,o);else {let i=r.__prepareOpenRtcBroadcastGrant(a.token,a.issuerPublicKey,o),v=await a.signBindingChallenge(i.signingBytes);n=r.__openOpenRtcBroadcast(a.token,a.issuerPublicKey,i.handle,v,void 0,o);}let l={...a.relay},c=n.state,s=false,d=false,h=false,u=null,f=new y({openSession:this.deps.openSession,observe:async i=>{if(!s){i.type==="opened"&&(c="live"),i.type==="failed"&&(c="retrying"),i.type==="closed"&&(c="closed");try{r.__observeOpenRtcBroadcastAdapter(n.handleId,i);}finally{await w();}}},onObject:async i=>s||!u?false:u.accept(i.sourceSlot,i.object)}),w=async()=>{if(!s){if(d){h=true;return}d=true;try{do{h=!1;let i=r.__takeOpenRtcBroadcastActions(n.handleId,32);for(let v of i)await f.apply(this.adapterAction(v,l));i.length===32&&(h=!0);}while(h)}finally{d=false;}}};u=new g(r,n.handleId,n.role,n.sourceSlots??[],w);let b={id:n.id,role:n.role,get state(){return c},media:u,getStats:async()=>({...r.__getOpenRtcBroadcastStats(n.handleId)}),close:async()=>{s||(s=true,f.dispose(),await u?.close(),r.__closeOpenRtcBroadcast(n.handleId),this.sessions.delete(b));}};this.sessions.add(b);try{return await w(),b}catch(i){throw await b.close(),i}}adapterAction(e,t){let r={broadcastGeneration:e.broadcastGeneration,grantGeneration:e.grantGeneration};if(e.type==="open"&&e.role)return {type:"open",role:e.role,relay:t,...r};if(e.type==="publish"&&e.sourceSlot&&e.object)return {type:"publish",sourceSlot:e.sourceSlot,object:e.object,discardable:e.discardable===true,control:e.control===true,...r};if(e.type==="subscribe"&&e.sourceSlots)return {type:"subscribe",sourceSlots:e.sourceSlots,...r};if(e.type==="close"&&e.reason)return {type:"close",reason:e.reason,...r};throw new Error("Rust returned an invalid broadcast adapter action")}};export{M as BrowserManagedBroadcastHost};
|