y-openrtc 1.0.0 → 2.0.0-rc.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.
- package/README.md +16 -18
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/provider.js +0 -3
- package/dist/roomRuntime.d.ts +4 -0
- package/dist/roomRuntime.js +63 -0
- package/dist/runtimePool.js +9 -75
- package/dist/types.d.ts +4 -19
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -12,11 +12,17 @@ pnpm add y-openrtc yjs
|
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
14
|
import * as Y from 'yjs';
|
|
15
|
+
import { OpenRTC } from 'openrtc';
|
|
15
16
|
import { OpenrtcProvider } from 'y-openrtc';
|
|
16
17
|
|
|
18
|
+
const rtc = OpenRTC({ apiKey: '<your public OpenRTC API key>' });
|
|
19
|
+
const room = await rtc.rooms.join('my-room', {
|
|
20
|
+
access: 'capability',
|
|
21
|
+
membership: 'ephemeral',
|
|
22
|
+
});
|
|
17
23
|
const doc = new Y.Doc();
|
|
18
24
|
const provider = new OpenrtcProvider('my-room', doc, {
|
|
19
|
-
|
|
25
|
+
room,
|
|
20
26
|
});
|
|
21
27
|
```
|
|
22
28
|
|
|
@@ -27,40 +33,32 @@ import * as Y from 'yjs';
|
|
|
27
33
|
import { OpenRTC } from 'openrtc';
|
|
28
34
|
import { OpenrtcProvider } from 'y-openrtc';
|
|
29
35
|
|
|
30
|
-
const
|
|
31
|
-
|
|
36
|
+
const room = await rtc.rooms.join('private-room', {
|
|
37
|
+
access: 'authenticated',
|
|
38
|
+
auth,
|
|
32
39
|
});
|
|
33
40
|
|
|
34
41
|
const doc = new Y.Doc();
|
|
35
42
|
const provider = new OpenrtcProvider('my-room', doc, {
|
|
36
|
-
|
|
43
|
+
room,
|
|
37
44
|
});
|
|
38
45
|
```
|
|
39
46
|
|
|
40
47
|
## Transport and strict-mode options
|
|
41
48
|
|
|
42
|
-
|
|
49
|
+
Configure advanced transports on the OpenRTC client, then pass the activated room:
|
|
43
50
|
|
|
44
51
|
```ts
|
|
45
|
-
const
|
|
52
|
+
const rtc = OpenRTC({
|
|
46
53
|
apiKey: '<your public OpenRTC API key>',
|
|
47
|
-
strictMode: true,
|
|
48
54
|
transports: {
|
|
49
55
|
iroh: true,
|
|
50
|
-
webrtc:
|
|
51
|
-
privacyMode: true,
|
|
52
|
-
useTurn: true,
|
|
53
|
-
},
|
|
56
|
+
webrtc: true,
|
|
54
57
|
moq: true,
|
|
55
58
|
},
|
|
56
|
-
turnCredentialsProvider: async () => ({
|
|
57
|
-
iceServers: [{
|
|
58
|
-
urls: ['turn:turn.example.com:3478?transport=udp'],
|
|
59
|
-
username: 'short-lived-user',
|
|
60
|
-
credential: 'short-lived-credential',
|
|
61
|
-
}],
|
|
62
|
-
}),
|
|
63
59
|
});
|
|
60
|
+
const room = await rtc.rooms.join('private-room', { access: 'capability' });
|
|
61
|
+
const provider = new OpenrtcProvider('private-room', doc, { room });
|
|
64
62
|
```
|
|
65
63
|
|
|
66
64
|
Keep TURN credentials server-generated and short lived. Do not commit `.env` files or long-lived secrets.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { OpenrtcProvider, } from './provider.js';
|
|
2
2
|
export { roomNameToOpenrtcRoomId } from './roomName.js';
|
|
3
|
-
export type {
|
|
3
|
+
export type { OpenrtcProviderEvents, OpenrtcProviderOptions, OpenrtcTransports, PeersEventPayload, StatusEventPayload, SyncedEventPayload, } from './types.js';
|
|
4
|
+
export { runtimeFromRoom } from './roomRuntime.js';
|
package/dist/index.js
CHANGED
package/dist/provider.js
CHANGED
|
@@ -264,9 +264,6 @@ export class OpenrtcProvider {
|
|
|
264
264
|
async connectInternal() {
|
|
265
265
|
const lease = acquireRuntimeLease({
|
|
266
266
|
...this.options,
|
|
267
|
-
authMode: this.options.authMode ?? 'anonymous',
|
|
268
|
-
allowAnonymousHostedDefaults: this.options.allowAnonymousHostedDefaults ?? !this.options.apiKey,
|
|
269
|
-
space: this.options.space ?? this.options.spaceKey ?? (!this.options.apiKey ? this.roomName : undefined),
|
|
270
267
|
});
|
|
271
268
|
this.runtimeLease = lease;
|
|
272
269
|
const runtime = await lease.ensureReady();
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { OpenRTCRoomHandle } from 'openrtc';
|
|
2
|
+
import type { RuntimeClient } from 'openrtc/runtime';
|
|
3
|
+
/** One-handle adapter; cast is isolated here so provider code cannot see legacy construction. */
|
|
4
|
+
export declare function runtimeFromRoom(room: OpenRTCRoomHandle): RuntimeClient;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
function normalized(value) {
|
|
2
|
+
return value.trim().toUpperCase();
|
|
3
|
+
}
|
|
4
|
+
function assertRoom(room, requested) {
|
|
5
|
+
if (normalized(room.id) !== normalized(requested)) {
|
|
6
|
+
throw new Error(`Activated OpenRTC room '${room.id}' cannot join '${requested}'.`);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
/** One-handle adapter; cast is isolated here so provider code cannot see legacy construction. */
|
|
10
|
+
export function runtimeFromRoom(room) {
|
|
11
|
+
const connections = () => room.diagnostics.connections();
|
|
12
|
+
const adapter = {
|
|
13
|
+
initialize: async () => undefined,
|
|
14
|
+
start: async () => undefined,
|
|
15
|
+
shutdown: async () => room.close(),
|
|
16
|
+
getNodeId: async () => {
|
|
17
|
+
const status = await room.diagnostics.status();
|
|
18
|
+
if (!status.localNodeId)
|
|
19
|
+
throw new Error('The activated OpenRTC room has no local peer identity.');
|
|
20
|
+
return status.localNodeId;
|
|
21
|
+
},
|
|
22
|
+
createRoom: async (roomId = room.id) => {
|
|
23
|
+
assertRoom(room, roomId);
|
|
24
|
+
return normalized(room.id);
|
|
25
|
+
},
|
|
26
|
+
joinRoom: async (roomId) => {
|
|
27
|
+
assertRoom(room, roomId);
|
|
28
|
+
return connections();
|
|
29
|
+
},
|
|
30
|
+
leaveRoom: async (roomId) => {
|
|
31
|
+
assertRoom(room, roomId);
|
|
32
|
+
await room.leave();
|
|
33
|
+
},
|
|
34
|
+
watchRoom: (roomId, callback) => {
|
|
35
|
+
assertRoom(room, roomId);
|
|
36
|
+
return room.peers.watch((peers) => callback(peers.map((peer) => ({
|
|
37
|
+
nodeId: peer.nodeId ?? peer.id,
|
|
38
|
+
userId: peer.userId,
|
|
39
|
+
ticket: peer.ticket,
|
|
40
|
+
joinedAt: Date.now(),
|
|
41
|
+
lastSeenAt: Date.now(),
|
|
42
|
+
}))));
|
|
43
|
+
},
|
|
44
|
+
onConnection: (callback) => {
|
|
45
|
+
const seen = new Set();
|
|
46
|
+
const publish = () => {
|
|
47
|
+
for (const connection of connections()) {
|
|
48
|
+
const id = connection.id ?? connection.remoteNodeId;
|
|
49
|
+
if (!id || seen.has(id))
|
|
50
|
+
continue;
|
|
51
|
+
seen.add(id);
|
|
52
|
+
callback(connection);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
publish();
|
|
56
|
+
return room.peers.watch(publish);
|
|
57
|
+
},
|
|
58
|
+
onConnectionStateChange: room.diagnostics.onConnectionStateChange,
|
|
59
|
+
getConnections: connections,
|
|
60
|
+
connectByTicket: ({ ticket, timeoutMs }) => room.peers.connect({ ticket, timeoutMs }),
|
|
61
|
+
};
|
|
62
|
+
return adapter;
|
|
63
|
+
}
|
package/dist/runtimePool.js
CHANGED
|
@@ -1,33 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
const ownedRuntimes = new Map();
|
|
1
|
+
import { runtimeFromRoom } from './roomRuntime.js';
|
|
3
2
|
const runtimeStartPromises = new WeakMap();
|
|
4
|
-
function stableStringify(value) {
|
|
5
|
-
if (value === null || typeof value !== 'object') {
|
|
6
|
-
return JSON.stringify(value);
|
|
7
|
-
}
|
|
8
|
-
if (Array.isArray(value)) {
|
|
9
|
-
return `[${value.map((item) => stableStringify(item)).join(',')}]`;
|
|
10
|
-
}
|
|
11
|
-
const entries = Object.entries(value)
|
|
12
|
-
.filter(([, current]) => current !== undefined)
|
|
13
|
-
.sort(([left], [right]) => left.localeCompare(right));
|
|
14
|
-
return `{${entries.map(([key, current]) => `${JSON.stringify(key)}:${stableStringify(current)}`).join(',')}}`;
|
|
15
|
-
}
|
|
16
|
-
function runtimePoolKey(options) {
|
|
17
|
-
const space = options.spaceKey ?? options.space;
|
|
18
|
-
return stableStringify({
|
|
19
|
-
apiKey: options.apiKey,
|
|
20
|
-
authMode: options.authMode,
|
|
21
|
-
allowAnonymousHostedDefaults: options.allowAnonymousHostedDefaults,
|
|
22
|
-
space,
|
|
23
|
-
hasSpaceTokenProvider: typeof options.spaceTokenProvider === 'function',
|
|
24
|
-
storagePrefix: options.storagePrefix,
|
|
25
|
-
nodeIdPersistence: options.nodeIdPersistence,
|
|
26
|
-
transports: options.transports,
|
|
27
|
-
strictMode: options.strictMode,
|
|
28
|
-
hasTurnCredentialsProvider: typeof options.turnCredentialsProvider === 'function',
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
3
|
async function ensureRuntimeReady(runtime) {
|
|
32
4
|
let startPromise = runtimeStartPromises.get(runtime);
|
|
33
5
|
if (!startPromise) {
|
|
@@ -41,53 +13,15 @@ async function ensureRuntimeReady(runtime) {
|
|
|
41
13
|
return runtime;
|
|
42
14
|
}
|
|
43
15
|
export function acquireRuntimeLease(options) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
owned: false,
|
|
49
|
-
ensureReady: () => ensureRuntimeReady(runtime),
|
|
50
|
-
release: async () => undefined,
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
const key = runtimePoolKey(options);
|
|
54
|
-
const space = options.spaceKey ?? options.space;
|
|
55
|
-
let entry = ownedRuntimes.get(key);
|
|
56
|
-
if (!entry) {
|
|
57
|
-
entry = {
|
|
58
|
-
runtime: OpenRTC({
|
|
59
|
-
apiKey: options.apiKey,
|
|
60
|
-
authMode: options.authMode,
|
|
61
|
-
allowAnonymousHostedDefaults: options.allowAnonymousHostedDefaults,
|
|
62
|
-
space,
|
|
63
|
-
spaceTokenProvider: options.spaceTokenProvider,
|
|
64
|
-
storagePrefix: options.storagePrefix,
|
|
65
|
-
nodeIdPersistence: options.nodeIdPersistence,
|
|
66
|
-
transports: options.transports,
|
|
67
|
-
strictMode: options.strictMode,
|
|
68
|
-
turnCredentialsProvider: options.turnCredentialsProvider,
|
|
69
|
-
}),
|
|
70
|
-
refs: 0,
|
|
71
|
-
};
|
|
72
|
-
ownedRuntimes.set(key, entry);
|
|
16
|
+
const runtime = options.runtime
|
|
17
|
+
?? (options.room ? runtimeFromRoom(options.room) : null);
|
|
18
|
+
if (!runtime) {
|
|
19
|
+
throw new Error('y-openrtc requires an activated OpenRTC 2.0 room handle or an explicit openrtc/runtime client.');
|
|
73
20
|
}
|
|
74
|
-
entry.refs += 1;
|
|
75
21
|
return {
|
|
76
|
-
runtime
|
|
77
|
-
owned:
|
|
78
|
-
ensureReady: () => ensureRuntimeReady(
|
|
79
|
-
release: async () =>
|
|
80
|
-
const current = ownedRuntimes.get(key);
|
|
81
|
-
if (!current) {
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
current.refs -= 1;
|
|
85
|
-
if (current.refs > 0) {
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
ownedRuntimes.delete(key);
|
|
89
|
-
runtimeStartPromises.delete(current.runtime);
|
|
90
|
-
current.runtime.stop();
|
|
91
|
-
},
|
|
22
|
+
runtime,
|
|
23
|
+
owned: false,
|
|
24
|
+
ensureReady: () => ensureRuntimeReady(runtime),
|
|
25
|
+
release: async () => undefined,
|
|
92
26
|
};
|
|
93
27
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,29 +1,15 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { OpenRTCOptions, OpenRTCRoomHandle } from 'openrtc';
|
|
2
2
|
import type { RuntimeClient } from 'openrtc/runtime';
|
|
3
3
|
import type { Awareness } from 'y-protocols/awareness';
|
|
4
|
-
type
|
|
5
|
-
export type OpenrtcTransports = OpenrtcClientOptions['transports'];
|
|
6
|
-
export type OpenrtcAuthMode = OpenrtcClientOptions['authMode'];
|
|
7
|
-
export type OpenrtcTurnCredentialsProvider = NonNullable<OpenrtcClientOptions>['turnCredentialsProvider'];
|
|
8
|
-
export type OpenrtcAllowAnonymousHostedDefaults = NonNullable<OpenrtcClientOptions>['allowAnonymousHostedDefaults'];
|
|
9
|
-
export type OpenrtcSpaceTokenProvider = NonNullable<OpenrtcClientOptions>['spaceTokenProvider'];
|
|
4
|
+
export type OpenrtcTransports = OpenRTCOptions['transports'];
|
|
10
5
|
export interface OpenrtcProviderOptions {
|
|
11
|
-
apiKey?: string;
|
|
12
6
|
runtime?: RuntimeClient;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
space?: string;
|
|
16
|
-
spaceKey?: string;
|
|
17
|
-
spaceTokenProvider?: OpenrtcSpaceTokenProvider;
|
|
7
|
+
/** Preferred 2.0 path: one already-activated collaborative room. */
|
|
8
|
+
room?: OpenRTCRoomHandle;
|
|
18
9
|
awareness?: Awareness;
|
|
19
10
|
password?: string | null;
|
|
20
11
|
maxConns?: number;
|
|
21
12
|
filterBcConns?: boolean;
|
|
22
|
-
storagePrefix?: string;
|
|
23
|
-
nodeIdPersistence?: 'persistent' | 'ephemeral';
|
|
24
|
-
transports?: OpenrtcTransports;
|
|
25
|
-
strictMode?: boolean;
|
|
26
|
-
turnCredentialsProvider?: OpenrtcTurnCredentialsProvider;
|
|
27
13
|
roomIdOverride?: string;
|
|
28
14
|
/**
|
|
29
15
|
* Ordered room ids to try when the preferred room is unavailable. This is
|
|
@@ -64,4 +50,3 @@ export interface OpenrtcProviderEvents {
|
|
|
64
50
|
synced: SyncedEventPayload;
|
|
65
51
|
peers: PeersEventPayload;
|
|
66
52
|
}
|
|
67
|
-
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "y-openrtc",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-rc.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -37,13 +37,13 @@
|
|
|
37
37
|
"build": "rm -rf dist && tsc",
|
|
38
38
|
"prepublishOnly": "pnpm run build",
|
|
39
39
|
"test": "vitest run tests",
|
|
40
|
-
"test:deterministic": "vitest run tests/TetrisSync.test.ts tests/TetrisPeerDiagnostic.test.ts tests/OpenrtcProvider.test.ts tests/PublicPackageGuard.test.ts tests/crypto.test.ts",
|
|
40
|
+
"test:deterministic": "vitest run tests/TetrisSync.test.ts tests/TetrisPeerDiagnostic.test.ts tests/OpenrtcProvider.test.ts tests/RoomRuntime.test.ts tests/PublicPackageGuard.test.ts tests/crypto.test.ts",
|
|
41
41
|
"test:watch": "vitest",
|
|
42
42
|
"test:live": "vitest run tests/OpenrtcProvider.live.test.ts"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"lib0": "^0.2.114",
|
|
46
|
-
"openrtc": "
|
|
46
|
+
"openrtc": "2.0.0-rc.0",
|
|
47
47
|
"y-protocols": "^1.0.6"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|