@gamention/pulse-core 0.2.0 → 0.3.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/dist/P2PManager-B21XQVk_.js +6709 -0
- package/dist/P2PManager-CcuTidGn.cjs +5 -0
- package/dist/index.d.ts +103 -0
- package/dist/pulse-core.cjs +1 -1
- package/dist/pulse-core.js +143 -88
- package/package.json +11 -9
package/dist/pulse-core.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
var
|
|
2
|
-
var f = (h, n, t) => n in h ?
|
|
3
|
-
var
|
|
4
|
-
import { DEFAULT_ENDPOINT as
|
|
5
|
-
class
|
|
1
|
+
var u = Object.defineProperty;
|
|
2
|
+
var f = (h, n, t) => n in h ? u(h, n, { enumerable: !0, configurable: !0, writable: !0, value: t }) : h[n] = t;
|
|
3
|
+
var r = (h, n, t) => f(h, typeof n != "symbol" ? n + "" : n, t);
|
|
4
|
+
import { DEFAULT_ENDPOINT as _, RECONNECT_BASE_DELAY_MS as m, RECONNECT_MAX_DELAY_MS as w, DEFAULT_ENV_CONFIG as d, CURSOR_THROTTLE_MS as l, PRESENCE_HEARTBEAT_MS as y } from "@gamention/pulse-shared";
|
|
5
|
+
class p {
|
|
6
6
|
constructor() {
|
|
7
|
-
|
|
7
|
+
r(this, "handlers", /* @__PURE__ */ new Map());
|
|
8
8
|
}
|
|
9
9
|
on(n, t) {
|
|
10
10
|
this.handlers.has(n) || this.handlers.set(n, /* @__PURE__ */ new Set());
|
|
@@ -17,22 +17,22 @@ class d {
|
|
|
17
17
|
}
|
|
18
18
|
emit(n, t) {
|
|
19
19
|
var e;
|
|
20
|
-
(e = this.handlers.get(n)) == null || e.forEach((
|
|
20
|
+
(e = this.handlers.get(n)) == null || e.forEach((i) => i(t));
|
|
21
21
|
}
|
|
22
22
|
removeAll() {
|
|
23
23
|
this.handlers.clear();
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
-
class
|
|
26
|
+
class v extends p {
|
|
27
27
|
constructor(t) {
|
|
28
28
|
super();
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
this.endpoint = t ??
|
|
29
|
+
r(this, "ws", null);
|
|
30
|
+
r(this, "endpoint");
|
|
31
|
+
r(this, "reconnectAttempt", 0);
|
|
32
|
+
r(this, "reconnectTimer", null);
|
|
33
|
+
r(this, "_state", "disconnected");
|
|
34
|
+
r(this, "permanentlyClosed", !1);
|
|
35
|
+
this.endpoint = t ?? _;
|
|
36
36
|
}
|
|
37
37
|
get state() {
|
|
38
38
|
return this._state;
|
|
@@ -67,7 +67,7 @@ class y extends d {
|
|
|
67
67
|
scheduleReconnect() {
|
|
68
68
|
if (this.permanentlyClosed) return;
|
|
69
69
|
const t = Math.min(
|
|
70
|
-
|
|
70
|
+
m * 2 ** this.reconnectAttempt,
|
|
71
71
|
w
|
|
72
72
|
);
|
|
73
73
|
this.reconnectAttempt++, this.reconnectTimer = setTimeout(() => {
|
|
@@ -75,35 +75,39 @@ class y extends d {
|
|
|
75
75
|
}, t);
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
-
class I extends
|
|
78
|
+
class I extends p {
|
|
79
79
|
constructor() {
|
|
80
80
|
super(...arguments);
|
|
81
81
|
/** HTTP base URL for resolving relative attachment paths (e.g. "http://localhost:4000"). */
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
82
|
+
r(this, "baseUrl", "");
|
|
83
|
+
r(this, "_user", null);
|
|
84
|
+
r(this, "_config", { ...d });
|
|
85
|
+
r(this, "_p2pConfig", null);
|
|
86
|
+
r(this, "_users", /* @__PURE__ */ new Map());
|
|
87
|
+
r(this, "_presence", /* @__PURE__ */ new Map());
|
|
88
|
+
r(this, "_threads", /* @__PURE__ */ new Map());
|
|
89
|
+
r(this, "_reactions", /* @__PURE__ */ new Map());
|
|
90
|
+
r(this, "_notifications", []);
|
|
91
|
+
r(this, "_activityLogs", []);
|
|
92
|
+
r(this, "_typing", /* @__PURE__ */ new Map());
|
|
93
|
+
r(this, "_viewports", /* @__PURE__ */ new Map());
|
|
94
|
+
r(this, "_selections", /* @__PURE__ */ new Map());
|
|
94
95
|
}
|
|
95
96
|
get user() {
|
|
96
97
|
return this._user;
|
|
97
98
|
}
|
|
99
|
+
get p2pConfig() {
|
|
100
|
+
return this._p2pConfig;
|
|
101
|
+
}
|
|
98
102
|
get config() {
|
|
99
103
|
return this._config;
|
|
100
104
|
}
|
|
101
105
|
/** Optimistically remove a comment from local state (before server round-trip). */
|
|
102
106
|
removeComment(t) {
|
|
103
|
-
for (const [e,
|
|
104
|
-
const
|
|
105
|
-
if (
|
|
106
|
-
|
|
107
|
+
for (const [e, i] of this._threads) {
|
|
108
|
+
const s = i.comments.findIndex((a) => a.id === t);
|
|
109
|
+
if (s !== -1) {
|
|
110
|
+
i.comments.splice(s, 1), i.comments.length === 0 && this._threads.delete(e), this.emit("threads", this.threads);
|
|
107
111
|
return;
|
|
108
112
|
}
|
|
109
113
|
}
|
|
@@ -122,7 +126,7 @@ class I extends d {
|
|
|
122
126
|
}
|
|
123
127
|
/** Optimistically mark a single notification as read. */
|
|
124
128
|
markNotificationRead(t) {
|
|
125
|
-
const e = this._notifications.find((
|
|
129
|
+
const e = this._notifications.find((i) => i.id === t);
|
|
126
130
|
e && !e.read && (e.read = !0, this.emit("notifications", this._notifications));
|
|
127
131
|
}
|
|
128
132
|
/** Optimistically mark all notifications as read. */
|
|
@@ -148,10 +152,10 @@ class I extends d {
|
|
|
148
152
|
getTypingUsers(t) {
|
|
149
153
|
const e = this._typing.get(t);
|
|
150
154
|
if (!e) return [];
|
|
151
|
-
const
|
|
152
|
-
for (const [
|
|
153
|
-
|
|
154
|
-
return
|
|
155
|
+
const i = Date.now(), s = [];
|
|
156
|
+
for (const [a, o] of e)
|
|
157
|
+
i - o < 3e3 && s.push(a);
|
|
158
|
+
return s;
|
|
155
159
|
}
|
|
156
160
|
get viewports() {
|
|
157
161
|
return this._viewports;
|
|
@@ -185,7 +189,7 @@ class I extends d {
|
|
|
185
189
|
handleMessage(t) {
|
|
186
190
|
switch (t.type) {
|
|
187
191
|
case "auth:ok":
|
|
188
|
-
this._config = t.config ?? { ...
|
|
192
|
+
this._config = t.config ?? { ...d }, this._p2pConfig = t.p2pConfig ?? null, this._user = t.user, this._users.clear();
|
|
189
193
|
for (const e of t.users) this._users.set(e.id, e);
|
|
190
194
|
this._presence.clear();
|
|
191
195
|
for (const e of t.presence)
|
|
@@ -194,8 +198,8 @@ class I extends d {
|
|
|
194
198
|
for (const e of t.threads) this._threads.set(e.id, this.resolveThread(e));
|
|
195
199
|
this._notifications = t.notifications, this._reactions.clear();
|
|
196
200
|
for (const e of t.reactions) {
|
|
197
|
-
const
|
|
198
|
-
|
|
201
|
+
const i = this._reactions.get(e.targetId) ?? [];
|
|
202
|
+
i.push(e), this._reactions.set(e.targetId, i);
|
|
199
203
|
}
|
|
200
204
|
this._activityLogs = [...t.activityLogs], this.emit("auth", t.user), this.emit("presence", this.presence), this.emit("threads", this.threads), this.emit("notifications", this._notifications), this.emit("reactions", null), this.emit("activity-logs", this._activityLogs);
|
|
201
205
|
break;
|
|
@@ -230,14 +234,14 @@ class I extends d {
|
|
|
230
234
|
case "comment:edited": {
|
|
231
235
|
const e = this._threads.get(t.threadId);
|
|
232
236
|
if (e) {
|
|
233
|
-
const
|
|
234
|
-
|
|
237
|
+
const i = e.comments.findIndex((s) => s.id === t.comment.id);
|
|
238
|
+
i !== -1 && (e.comments[i] = this.resolveComment(t.comment)), this.emit("threads", this.threads);
|
|
235
239
|
}
|
|
236
240
|
break;
|
|
237
241
|
}
|
|
238
242
|
case "comment:deleted": {
|
|
239
243
|
const e = this._threads.get(t.threadId);
|
|
240
|
-
e && (e.comments = e.comments.filter((
|
|
244
|
+
e && (e.comments = e.comments.filter((i) => i.id !== t.commentId), e.comments.length === 0 && this._threads.delete(t.threadId), this.emit("threads", this.threads));
|
|
241
245
|
break;
|
|
242
246
|
}
|
|
243
247
|
case "thread:resolved": {
|
|
@@ -259,10 +263,10 @@ class I extends d {
|
|
|
259
263
|
case "reaction:removed": {
|
|
260
264
|
const e = this._reactions.get(t.targetId);
|
|
261
265
|
if (e) {
|
|
262
|
-
const
|
|
263
|
-
this._reactions.set(t.targetId,
|
|
266
|
+
const i = e.filter((s) => s.id !== t.reactionId);
|
|
267
|
+
this._reactions.set(t.targetId, i), this.emit("reactions", {
|
|
264
268
|
targetId: t.targetId,
|
|
265
|
-
reactions:
|
|
269
|
+
reactions: i
|
|
266
270
|
});
|
|
267
271
|
}
|
|
268
272
|
break;
|
|
@@ -318,26 +322,30 @@ class I extends d {
|
|
|
318
322
|
}
|
|
319
323
|
}
|
|
320
324
|
reset() {
|
|
321
|
-
this._user = null, this._config = { ...
|
|
325
|
+
this._user = null, this._config = { ...d }, this._p2pConfig = null, this._users.clear(), this._presence.clear(), this._threads.clear(), this._reactions.clear(), this._notifications = [], this._activityLogs = [], this._typing.clear(), this._viewports.clear(), this._selections.clear();
|
|
322
326
|
}
|
|
323
327
|
}
|
|
324
|
-
class
|
|
328
|
+
class k extends p {
|
|
325
329
|
constructor(t) {
|
|
326
|
-
var
|
|
330
|
+
var i;
|
|
327
331
|
super();
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
332
|
+
r(this, "state");
|
|
333
|
+
r(this, "connection");
|
|
334
|
+
r(this, "config");
|
|
335
|
+
r(this, "heartbeatTimer", null);
|
|
336
|
+
r(this, "lastCursorSend", 0);
|
|
337
|
+
r(this, "pendingCursor", null);
|
|
338
|
+
r(this, "cursorTimer", null);
|
|
339
|
+
r(this, "_p2p", null);
|
|
340
|
+
r(this, "_p2pInstance", null);
|
|
341
|
+
r(this, "p2pEnabled");
|
|
342
|
+
r(this, "iceServers");
|
|
335
343
|
this.config = t, this.state = new I(), this.state.baseUrl = (t.endpoint ?? "").replace(/^ws(s?):/, "http$1:").replace(/\/$/, "");
|
|
336
|
-
const e = ((
|
|
337
|
-
this.connection = new
|
|
338
|
-
this.state.handleMessage(
|
|
339
|
-
}), this.connection.on("state", (
|
|
340
|
-
this.emit("connection",
|
|
344
|
+
const e = ((i = t.endpoint) == null ? void 0 : i.replace(/^http/, "ws")) ?? void 0;
|
|
345
|
+
this.connection = new v(e), this.p2pEnabled = t.p2p ?? !1, this.iceServers = t.iceServers ?? [{ urls: "stun:stun.l.google.com:19302" }], this.connection.on("message", (s) => {
|
|
346
|
+
this.state.handleMessage(s), this.emit(s.type, s), s.type === "auth:error" && this.connection.permanentDisconnect(), this._p2pInstance && (s.type === "signal:offer" ? this._p2pInstance.handleSignalOffer(s.fromUserId, s.sdp) : s.type === "signal:answer" ? this._p2pInstance.handleSignalAnswer(s.fromUserId, s.sdp) : s.type === "signal:ice" ? this._p2pInstance.handleIceCandidate(s.fromUserId, s.candidate) : s.type === "p2p:sync" ? this._p2pInstance.handleP2PSync(s.fromUserId, s.update) : s.type === "presence:join" ? this._p2pInstance.onPeerJoined(s.user.user.id) : s.type === "presence:leave" && this._p2pInstance.onPeerLeft(s.userId));
|
|
347
|
+
}), this.connection.on("state", (s) => {
|
|
348
|
+
this.emit("connection", s), s === "connected" ? (this.authenticate(), this.startHeartbeat()) : s === "disconnected" && this.stopHeartbeat();
|
|
341
349
|
});
|
|
342
350
|
}
|
|
343
351
|
/** Current WebSocket connection state. */
|
|
@@ -351,7 +359,8 @@ class T extends d {
|
|
|
351
359
|
this.stopHeartbeat(), this.cursorTimer && (clearTimeout(this.cursorTimer), this.cursorTimer = null), this.connection.disconnect(), this.state.reset();
|
|
352
360
|
}
|
|
353
361
|
destroy() {
|
|
354
|
-
|
|
362
|
+
var t;
|
|
363
|
+
(t = this._p2pInstance) == null || t.destroy(), this._p2pInstance = null, this._p2p = null, this.disconnect(), this.removeAll(), this.state.removeAll(), this.connection.removeAll();
|
|
355
364
|
}
|
|
356
365
|
authenticate() {
|
|
357
366
|
this.send({
|
|
@@ -381,29 +390,29 @@ class T extends d {
|
|
|
381
390
|
startHeartbeat() {
|
|
382
391
|
this.heartbeatTimer || (this.heartbeatTimer = setInterval(() => {
|
|
383
392
|
this.send({ type: "presence:update", status: "online" });
|
|
384
|
-
},
|
|
393
|
+
}, y));
|
|
385
394
|
}
|
|
386
395
|
stopHeartbeat() {
|
|
387
396
|
this.heartbeatTimer && (clearInterval(this.heartbeatTimer), this.heartbeatTimer = null);
|
|
388
397
|
}
|
|
389
398
|
// ── Threads & Comments ──
|
|
390
399
|
createThread(t, e = {}) {
|
|
391
|
-
const
|
|
400
|
+
const i = crypto.randomUUID();
|
|
392
401
|
return this.send({
|
|
393
402
|
type: "thread:create",
|
|
394
|
-
id:
|
|
403
|
+
id: i,
|
|
395
404
|
body: t,
|
|
396
405
|
mentions: e.mentions ?? [],
|
|
397
406
|
position: e.position ?? null,
|
|
398
407
|
attachmentIds: e.attachmentIds
|
|
399
|
-
}),
|
|
408
|
+
}), i;
|
|
400
409
|
}
|
|
401
|
-
reply(t, e,
|
|
402
|
-
const
|
|
403
|
-
return this.send({ type: "comment:create", threadId: t, id:
|
|
410
|
+
reply(t, e, i = [], s) {
|
|
411
|
+
const a = crypto.randomUUID();
|
|
412
|
+
return this.send({ type: "comment:create", threadId: t, id: a, body: e, mentions: i, attachmentIds: s }), a;
|
|
404
413
|
}
|
|
405
|
-
editComment(t, e,
|
|
406
|
-
this.send({ type: "comment:edit", commentId: t, body: e, mentions:
|
|
414
|
+
editComment(t, e, i = []) {
|
|
415
|
+
this.send({ type: "comment:edit", commentId: t, body: e, mentions: i });
|
|
407
416
|
}
|
|
408
417
|
deleteComment(t) {
|
|
409
418
|
this.state.removeComment(t), this.send({ type: "comment:delete", commentId: t });
|
|
@@ -412,8 +421,8 @@ class T extends d {
|
|
|
412
421
|
this.send({ type: "thread:resolve", threadId: t, resolved: e });
|
|
413
422
|
}
|
|
414
423
|
// ── Reactions ──
|
|
415
|
-
addReaction(t, e,
|
|
416
|
-
this.send({ type: "reaction:add", targetId: t, targetType: e, emoji:
|
|
424
|
+
addReaction(t, e, i) {
|
|
425
|
+
this.send({ type: "reaction:add", targetId: t, targetType: e, emoji: i });
|
|
417
426
|
}
|
|
418
427
|
removeReaction(t) {
|
|
419
428
|
this.send({ type: "reaction:remove", reactionId: t });
|
|
@@ -446,39 +455,85 @@ class T extends d {
|
|
|
446
455
|
this.send({ type: "emoji:drop", emoji: t, position: e });
|
|
447
456
|
}
|
|
448
457
|
// ── Drawing ──
|
|
449
|
-
drawStroke(t, e,
|
|
450
|
-
this.send({ type: "draw:stroke", points: t, color: e, width:
|
|
458
|
+
drawStroke(t, e, i) {
|
|
459
|
+
this.send({ type: "draw:stroke", points: t, color: e, width: i });
|
|
451
460
|
}
|
|
452
461
|
clearDrawing() {
|
|
453
462
|
this.send({ type: "draw:clear" });
|
|
454
463
|
}
|
|
455
464
|
// ── File Upload ──
|
|
456
465
|
async uploadFile(t) {
|
|
457
|
-
const e = typeof window < "u" ? window.location.origin : "",
|
|
458
|
-
|
|
459
|
-
const
|
|
466
|
+
const e = typeof window < "u" ? window.location.origin : "", i = (this.config.endpoint ?? e).replace(/^ws(s?):/, "http$1:"), s = new FormData();
|
|
467
|
+
s.append("file", t);
|
|
468
|
+
const a = await fetch(`${i}/api/v1/upload`, {
|
|
460
469
|
method: "POST",
|
|
461
470
|
headers: {
|
|
462
471
|
"X-Pulse-Key": this.config.apiKey,
|
|
463
472
|
"X-Pulse-Token": this.config.token
|
|
464
473
|
},
|
|
465
|
-
body:
|
|
474
|
+
body: s
|
|
466
475
|
});
|
|
467
|
-
if (!
|
|
468
|
-
const
|
|
469
|
-
throw new Error(
|
|
476
|
+
if (!a.ok) {
|
|
477
|
+
const c = await a.json().catch(() => ({ error: "Upload failed" }));
|
|
478
|
+
throw new Error(c.error ?? "Upload failed");
|
|
470
479
|
}
|
|
471
|
-
const
|
|
472
|
-
return
|
|
480
|
+
const o = await a.json();
|
|
481
|
+
return o.url && !o.url.startsWith("http") && (o.url = `${i}${o.url}`), o.thumbnailUrl && !o.thumbnailUrl.startsWith("http") && (o.thumbnailUrl = `${i}${o.thumbnailUrl}`), o;
|
|
473
482
|
}
|
|
474
483
|
// ── Presence control ──
|
|
475
484
|
setAppearOffline(t) {
|
|
476
485
|
t ? (this.stopHeartbeat(), this.send({ type: "presence:update", status: "idle" })) : (this.startHeartbeat(), this.send({ type: "presence:update", status: "online" }));
|
|
477
486
|
}
|
|
487
|
+
// ── P2P ──
|
|
488
|
+
/** Lazy-loaded P2P manager. Returns a promise that resolves to the P2PManager instance. */
|
|
489
|
+
get p2p() {
|
|
490
|
+
return this.p2pEnabled ? (this._p2p || (this._p2p = this.initP2P()), this._p2p) : Promise.reject(
|
|
491
|
+
new Error("P2P is not enabled. Pass { p2p: true } in PulseConfig.")
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
async initP2P() {
|
|
495
|
+
const t = await new Promise((a, o) => {
|
|
496
|
+
if (this.state.user && this.state.p2pConfig) {
|
|
497
|
+
a({
|
|
498
|
+
userId: this.state.user.id,
|
|
499
|
+
p2pConfig: this.state.p2pConfig
|
|
500
|
+
});
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
const c = this.state.on("auth", () => {
|
|
504
|
+
if (c(), !this.state.p2pConfig) {
|
|
505
|
+
o(new Error("P2P is not enabled for this environment."));
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
a({
|
|
509
|
+
userId: this.state.user.id,
|
|
510
|
+
p2pConfig: this.state.p2pConfig
|
|
511
|
+
});
|
|
512
|
+
});
|
|
513
|
+
});
|
|
514
|
+
let e = this.iceServers;
|
|
515
|
+
try {
|
|
516
|
+
const a = await fetch(`${this.state.baseUrl}/api/v1/turn-credentials`, {
|
|
517
|
+
headers: { Authorization: `Bearer ${this.config.token}` }
|
|
518
|
+
});
|
|
519
|
+
a.ok && (e = (await a.json()).iceServers);
|
|
520
|
+
} catch {
|
|
521
|
+
}
|
|
522
|
+
const { P2PManager: i } = await import("./P2PManager-B21XQVk_.js"), s = new i({
|
|
523
|
+
roomId: this.config.room,
|
|
524
|
+
userId: t.userId,
|
|
525
|
+
baseUrl: this.state.baseUrl,
|
|
526
|
+
authToken: this.config.token,
|
|
527
|
+
p2pConfig: t.p2pConfig,
|
|
528
|
+
iceServers: e,
|
|
529
|
+
sendWS: (a) => this.send(a)
|
|
530
|
+
});
|
|
531
|
+
return this._p2pInstance = s, await s.initialize(), s;
|
|
532
|
+
}
|
|
478
533
|
}
|
|
479
534
|
export {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
535
|
+
v as Connection,
|
|
536
|
+
p as Emitter,
|
|
537
|
+
k as PulseClient,
|
|
483
538
|
I as StateManager
|
|
484
539
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gamention/pulse-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Core client SDK for Pulse — WebSocket connection, state management, and API for real-time collaboration",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/pulse-core.cjs",
|
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
"files": [
|
|
17
17
|
"dist"
|
|
18
18
|
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "vite build",
|
|
21
|
+
"dev": "vite build --watch",
|
|
22
|
+
"clean": "rm -rf dist"
|
|
23
|
+
},
|
|
19
24
|
"keywords": [
|
|
20
25
|
"pulse",
|
|
21
26
|
"collaboration",
|
|
@@ -36,17 +41,14 @@
|
|
|
36
41
|
"access": "public"
|
|
37
42
|
},
|
|
38
43
|
"peerDependencies": {
|
|
39
|
-
"@gamention/pulse-shared": "
|
|
44
|
+
"@gamention/pulse-shared": "workspace:*"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"yjs": "^13.6.30"
|
|
40
48
|
},
|
|
41
|
-
"dependencies": {},
|
|
42
49
|
"devDependencies": {
|
|
43
50
|
"typescript": "^5.7.0",
|
|
44
51
|
"vite": "^6.0.0",
|
|
45
52
|
"vite-plugin-dts": "^4.3.0"
|
|
46
|
-
},
|
|
47
|
-
"scripts": {
|
|
48
|
-
"build": "vite build",
|
|
49
|
-
"dev": "vite build --watch",
|
|
50
|
-
"clean": "rm -rf dist"
|
|
51
53
|
}
|
|
52
|
-
}
|
|
54
|
+
}
|