@signe/room 1.0.1 → 1.0.2
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/index.js +206 -181
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
|
|
1
4
|
// src/decorators.ts
|
|
2
5
|
function Action(name, bodyValidation) {
|
|
3
6
|
return function(target, propertyKey) {
|
|
@@ -10,6 +13,7 @@ function Action(name, bodyValidation) {
|
|
|
10
13
|
});
|
|
11
14
|
};
|
|
12
15
|
}
|
|
16
|
+
__name(Action, "Action");
|
|
13
17
|
function Room(options) {
|
|
14
18
|
return function(target) {
|
|
15
19
|
target.path = options.path;
|
|
@@ -18,12 +22,14 @@ function Room(options) {
|
|
|
18
22
|
target.throttleSync = options.throttleSync;
|
|
19
23
|
};
|
|
20
24
|
}
|
|
25
|
+
__name(Room, "Room");
|
|
21
26
|
|
|
22
27
|
// ../sync/src/utils.ts
|
|
23
28
|
function isClass(obj) {
|
|
24
29
|
return typeof obj === "function" && obj.prototype && obj.prototype.constructor === obj;
|
|
25
30
|
}
|
|
26
|
-
|
|
31
|
+
__name(isClass, "isClass");
|
|
32
|
+
var isObject = /* @__PURE__ */ __name((item) => item && typeof item === "object" && !Array.isArray(item) && item !== null, "isObject");
|
|
27
33
|
function generateShortUUID() {
|
|
28
34
|
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
29
35
|
let uuid = "";
|
|
@@ -33,13 +39,15 @@ function generateShortUUID() {
|
|
|
33
39
|
}
|
|
34
40
|
return uuid;
|
|
35
41
|
}
|
|
42
|
+
__name(generateShortUUID, "generateShortUUID");
|
|
36
43
|
|
|
37
44
|
// src/mock.ts
|
|
38
|
-
var MockPartySocket = class {
|
|
39
|
-
|
|
40
|
-
this
|
|
41
|
-
this.id = generateShortUUID();
|
|
45
|
+
var MockPartySocket = class MockPartySocket2 {
|
|
46
|
+
static {
|
|
47
|
+
__name(this, "MockPartySocket");
|
|
42
48
|
}
|
|
49
|
+
events = /* @__PURE__ */ new Map();
|
|
50
|
+
id = generateShortUUID();
|
|
43
51
|
addEventListener(event, cb) {
|
|
44
52
|
this.events.set(event, cb);
|
|
45
53
|
}
|
|
@@ -50,10 +58,11 @@ var MockPartySocket = class {
|
|
|
50
58
|
this.events.get(event)?.(data);
|
|
51
59
|
}
|
|
52
60
|
};
|
|
53
|
-
var MockStorage = class {
|
|
54
|
-
|
|
55
|
-
this
|
|
61
|
+
var MockStorage = class MockStorage2 {
|
|
62
|
+
static {
|
|
63
|
+
__name(this, "MockStorage");
|
|
56
64
|
}
|
|
65
|
+
storage = /* @__PURE__ */ new Map();
|
|
57
66
|
async get(key) {
|
|
58
67
|
return this.storage.get(key);
|
|
59
68
|
}
|
|
@@ -64,7 +73,13 @@ var MockStorage = class {
|
|
|
64
73
|
return this.storage;
|
|
65
74
|
}
|
|
66
75
|
};
|
|
67
|
-
var MockPartyRoom = class {
|
|
76
|
+
var MockPartyRoom = class MockPartyRoom2 {
|
|
77
|
+
static {
|
|
78
|
+
__name(this, "MockPartyRoom");
|
|
79
|
+
}
|
|
80
|
+
id;
|
|
81
|
+
clients;
|
|
82
|
+
storage;
|
|
68
83
|
constructor(id) {
|
|
69
84
|
this.id = id;
|
|
70
85
|
this.clients = /* @__PURE__ */ new Map();
|
|
@@ -86,9 +101,10 @@ var MockPartyRoom = class {
|
|
|
86
101
|
}
|
|
87
102
|
};
|
|
88
103
|
var MockConnection = class {
|
|
89
|
-
|
|
90
|
-
this
|
|
104
|
+
static {
|
|
105
|
+
__name(this, "MockConnection");
|
|
91
106
|
}
|
|
107
|
+
state = {};
|
|
92
108
|
setState(value) {
|
|
93
109
|
this.state = value;
|
|
94
110
|
}
|
|
@@ -101,33 +117,29 @@ import { dset as dset2 } from "dset";
|
|
|
101
117
|
import z from "zod";
|
|
102
118
|
|
|
103
119
|
// ../sync/src/core.ts
|
|
104
|
-
import {
|
|
105
|
-
|
|
106
|
-
ObjectSubject,
|
|
107
|
-
isSignal
|
|
108
|
-
} from "@signe/reactive";
|
|
109
|
-
var syncClass = (instance, options = {}) => {
|
|
120
|
+
import { ArraySubject, ObjectSubject, isSignal } from "@signe/reactive";
|
|
121
|
+
var syncClass = /* @__PURE__ */ __name((instance, options = {}) => {
|
|
110
122
|
const cacheSync = /* @__PURE__ */ new Map();
|
|
111
123
|
const cachePersist = /* @__PURE__ */ new Set();
|
|
112
124
|
instance.$valuesChanges = {
|
|
113
|
-
set: (path, value) => {
|
|
125
|
+
set: /* @__PURE__ */ __name((path, value) => {
|
|
114
126
|
cacheSync.set(path, value);
|
|
115
127
|
options.onSync?.(cacheSync);
|
|
116
|
-
},
|
|
117
|
-
setPersist: (path) => {
|
|
128
|
+
}, "set"),
|
|
129
|
+
setPersist: /* @__PURE__ */ __name((path) => {
|
|
118
130
|
if (path == "") path = ".";
|
|
119
131
|
cachePersist.add(path);
|
|
120
132
|
options.onPersist?.(cachePersist);
|
|
121
|
-
},
|
|
122
|
-
has: (path) => {
|
|
133
|
+
}, "setPersist"),
|
|
134
|
+
has: /* @__PURE__ */ __name((path) => {
|
|
123
135
|
return cacheSync.has(path);
|
|
124
|
-
},
|
|
125
|
-
get: (path) => {
|
|
136
|
+
}, "has"),
|
|
137
|
+
get: /* @__PURE__ */ __name((path) => {
|
|
126
138
|
return cacheSync.get(path);
|
|
127
|
-
}
|
|
139
|
+
}, "get")
|
|
128
140
|
};
|
|
129
141
|
createSyncClass(instance);
|
|
130
|
-
};
|
|
142
|
+
}, "syncClass");
|
|
131
143
|
function createStatesSnapshot(instance) {
|
|
132
144
|
let persistObject = {};
|
|
133
145
|
if (instance.$snapshot) {
|
|
@@ -145,6 +157,7 @@ function createStatesSnapshot(instance) {
|
|
|
145
157
|
}
|
|
146
158
|
return persistObject;
|
|
147
159
|
}
|
|
160
|
+
__name(createStatesSnapshot, "createStatesSnapshot");
|
|
148
161
|
function setMetadata(target, key, value) {
|
|
149
162
|
const meta = target.constructor._propertyMetadata;
|
|
150
163
|
const propId = meta?.get(key);
|
|
@@ -156,7 +169,8 @@ function setMetadata(target, key, value) {
|
|
|
156
169
|
}
|
|
157
170
|
}
|
|
158
171
|
}
|
|
159
|
-
|
|
172
|
+
__name(setMetadata, "setMetadata");
|
|
173
|
+
var createSyncClass = /* @__PURE__ */ __name((currentClass, parentKey = null, parentClass = null, path = "") => {
|
|
160
174
|
currentClass.$path = path;
|
|
161
175
|
if (parentClass) {
|
|
162
176
|
currentClass.$valuesChanges = parentClass.$valuesChanges;
|
|
@@ -171,7 +185,9 @@ var createSyncClass = (currentClass, parentKey = null, parentClass = null, path
|
|
|
171
185
|
const persist = signal.options.persist ?? true;
|
|
172
186
|
let value = signal();
|
|
173
187
|
if (isObject(value) || Array.isArray(value)) {
|
|
174
|
-
value = {
|
|
188
|
+
value = {
|
|
189
|
+
...value
|
|
190
|
+
};
|
|
175
191
|
}
|
|
176
192
|
const newPath = (path ? path + "." : "") + key;
|
|
177
193
|
if (syncToClient) {
|
|
@@ -182,7 +198,7 @@ var createSyncClass = (currentClass, parentKey = null, parentClass = null, path
|
|
|
182
198
|
}
|
|
183
199
|
}
|
|
184
200
|
}
|
|
185
|
-
};
|
|
201
|
+
}, "createSyncClass");
|
|
186
202
|
|
|
187
203
|
// ../sync/src/load.ts
|
|
188
204
|
import { isSignal as isSignal2 } from "@signe/reactive";
|
|
@@ -193,12 +209,14 @@ function load(rootInstance, values, valueIsObject) {
|
|
|
193
209
|
loadFromPaths(rootInstance, values);
|
|
194
210
|
}
|
|
195
211
|
}
|
|
212
|
+
__name(load, "load");
|
|
196
213
|
function loadFromPaths(rootInstance, values) {
|
|
197
214
|
for (const [path, value] of Object.entries(values)) {
|
|
198
215
|
const parts = path.split(".");
|
|
199
216
|
loadValue(rootInstance, parts, value);
|
|
200
217
|
}
|
|
201
218
|
}
|
|
219
|
+
__name(loadFromPaths, "loadFromPaths");
|
|
202
220
|
function loadFromObject(rootInstance, values, currentPath = "") {
|
|
203
221
|
for (const [key, value] of Object.entries(values)) {
|
|
204
222
|
const newPath = currentPath ? `${currentPath}.${key}` : key;
|
|
@@ -210,6 +228,7 @@ function loadFromObject(rootInstance, values, currentPath = "") {
|
|
|
210
228
|
}
|
|
211
229
|
}
|
|
212
230
|
}
|
|
231
|
+
__name(loadFromObject, "loadFromObject");
|
|
213
232
|
function loadValue(rootInstance, parts, value) {
|
|
214
233
|
let current = rootInstance;
|
|
215
234
|
for (let i = 0; i < parts.length; i++) {
|
|
@@ -229,10 +248,7 @@ function loadValue(rootInstance, parts, value) {
|
|
|
229
248
|
}
|
|
230
249
|
const currentValue = current[part];
|
|
231
250
|
if (currentValue === void 0) {
|
|
232
|
-
const parentInstance = getByPath(
|
|
233
|
-
rootInstance,
|
|
234
|
-
parts.slice(0, i).join(".")
|
|
235
|
-
);
|
|
251
|
+
const parentInstance = getByPath(rootInstance, parts.slice(0, i).join("."));
|
|
236
252
|
const classType = parentInstance?.options?.classType;
|
|
237
253
|
if (classType) {
|
|
238
254
|
current[part] = !isClass(classType) ? classType(part) : new classType();
|
|
@@ -245,6 +261,7 @@ function loadValue(rootInstance, parts, value) {
|
|
|
245
261
|
}
|
|
246
262
|
}
|
|
247
263
|
}
|
|
264
|
+
__name(loadValue, "loadValue");
|
|
248
265
|
function getByPath(root, path) {
|
|
249
266
|
const parts = path.split(".");
|
|
250
267
|
let current = root;
|
|
@@ -260,18 +277,22 @@ function getByPath(root, path) {
|
|
|
260
277
|
}
|
|
261
278
|
return current;
|
|
262
279
|
}
|
|
280
|
+
__name(getByPath, "getByPath");
|
|
263
281
|
|
|
264
282
|
// src/utils.ts
|
|
265
283
|
import { dset } from "dset";
|
|
266
284
|
function isPromise(value) {
|
|
267
285
|
return value instanceof Promise;
|
|
268
286
|
}
|
|
287
|
+
__name(isPromise, "isPromise");
|
|
269
288
|
async function awaitReturn(val) {
|
|
270
289
|
return isPromise(val) ? await val : val;
|
|
271
290
|
}
|
|
291
|
+
__name(awaitReturn, "awaitReturn");
|
|
272
292
|
function isClass2(obj) {
|
|
273
293
|
return typeof obj === "function" && obj.prototype && obj.prototype.constructor === obj;
|
|
274
294
|
}
|
|
295
|
+
__name(isClass2, "isClass");
|
|
275
296
|
function throttle(func, wait) {
|
|
276
297
|
let timeout = null;
|
|
277
298
|
let lastArgs = null;
|
|
@@ -290,6 +311,7 @@ function throttle(func, wait) {
|
|
|
290
311
|
}
|
|
291
312
|
};
|
|
292
313
|
}
|
|
314
|
+
__name(throttle, "throttle");
|
|
293
315
|
function extractParams(pattern, str) {
|
|
294
316
|
const regexPattern = pattern.replace(/{(\w+)}/g, "(?<$1>[\\w-]+)");
|
|
295
317
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
@@ -302,6 +324,7 @@ function extractParams(pattern, str) {
|
|
|
302
324
|
return null;
|
|
303
325
|
}
|
|
304
326
|
}
|
|
327
|
+
__name(extractParams, "extractParams");
|
|
305
328
|
function dremove(obj, keys) {
|
|
306
329
|
if (typeof keys === "string") {
|
|
307
330
|
keys = keys.split(".");
|
|
@@ -321,6 +344,7 @@ function dremove(obj, keys) {
|
|
|
321
344
|
delete t[k];
|
|
322
345
|
}
|
|
323
346
|
}
|
|
347
|
+
__name(dremove, "dremove");
|
|
324
348
|
function buildObject(valuesMap, allMemory) {
|
|
325
349
|
let memoryObj = {};
|
|
326
350
|
for (let path of valuesMap.keys()) {
|
|
@@ -334,6 +358,7 @@ function buildObject(valuesMap, allMemory) {
|
|
|
334
358
|
}
|
|
335
359
|
return memoryObj;
|
|
336
360
|
}
|
|
361
|
+
__name(buildObject, "buildObject");
|
|
337
362
|
|
|
338
363
|
// src/server.ts
|
|
339
364
|
var Message = z.object({
|
|
@@ -341,70 +366,76 @@ var Message = z.object({
|
|
|
341
366
|
value: z.any()
|
|
342
367
|
});
|
|
343
368
|
var Server = class {
|
|
369
|
+
static {
|
|
370
|
+
__name(this, "Server");
|
|
371
|
+
}
|
|
372
|
+
room;
|
|
373
|
+
subRoom;
|
|
374
|
+
rooms;
|
|
344
375
|
/**
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
376
|
+
* @constructor
|
|
377
|
+
* @param {Party.Room} room - The room object representing the current game or application instance.
|
|
378
|
+
*
|
|
379
|
+
* @example
|
|
380
|
+
* ```typescript
|
|
381
|
+
* const server = new MyServer(new ServerIo("game"));
|
|
382
|
+
* ```
|
|
383
|
+
*/
|
|
353
384
|
constructor(room) {
|
|
354
385
|
this.room = room;
|
|
355
386
|
this.subRoom = null;
|
|
356
387
|
this.rooms = [];
|
|
357
388
|
}
|
|
358
389
|
/**
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
390
|
+
* @readonly
|
|
391
|
+
* @property {boolean} isHibernate - Indicates whether the server is in hibernate mode.
|
|
392
|
+
*
|
|
393
|
+
* @example
|
|
394
|
+
* ```typescript
|
|
395
|
+
* if (!server.isHibernate) {
|
|
396
|
+
* console.log("Server is active");
|
|
397
|
+
* }
|
|
398
|
+
* ```
|
|
399
|
+
*/
|
|
369
400
|
get isHibernate() {
|
|
370
401
|
return !!this["options"]?.hibernate;
|
|
371
402
|
}
|
|
372
403
|
/**
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
404
|
+
* @method onStart
|
|
405
|
+
* @async
|
|
406
|
+
* @description Initializes the server and creates the initial room if not in hibernate mode.
|
|
407
|
+
* @returns {Promise<void>}
|
|
408
|
+
*
|
|
409
|
+
* @example
|
|
410
|
+
* ```typescript
|
|
411
|
+
* async function initServer() {
|
|
412
|
+
* await server.onStart();
|
|
413
|
+
* console.log("Server started");
|
|
414
|
+
* }
|
|
415
|
+
* ```
|
|
416
|
+
*/
|
|
386
417
|
async onStart() {
|
|
387
418
|
if (!this.isHibernate) {
|
|
388
419
|
this.subRoom = await this.createRoom();
|
|
389
420
|
}
|
|
390
421
|
}
|
|
391
422
|
/**
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
423
|
+
* @method createRoom
|
|
424
|
+
* @private
|
|
425
|
+
* @async
|
|
426
|
+
* @param {CreateRoomOptions} [options={}] - Options for creating the room.
|
|
427
|
+
* @returns {Promise<Object>} The created room instance.
|
|
428
|
+
* @throws {Error} If no matching room is found.
|
|
429
|
+
*
|
|
430
|
+
* @example
|
|
431
|
+
* ```typescript
|
|
432
|
+
* // This method is private and called internally
|
|
433
|
+
* async function internalCreateRoom() {
|
|
434
|
+
* const room = await this.createRoom({ getMemoryAll: true });
|
|
435
|
+
* console.log("Room created:", room);
|
|
436
|
+
* }
|
|
437
|
+
* ```
|
|
438
|
+
*/
|
|
408
439
|
async createRoom(options = {}) {
|
|
409
440
|
let instance;
|
|
410
441
|
let init = true;
|
|
@@ -418,7 +449,7 @@ var Server = class {
|
|
|
418
449
|
if (!instance) {
|
|
419
450
|
throw new Error("Room not found");
|
|
420
451
|
}
|
|
421
|
-
const loadMemory = async () => {
|
|
452
|
+
const loadMemory = /* @__PURE__ */ __name(async () => {
|
|
422
453
|
const root = await this.room.storage.get(".");
|
|
423
454
|
const memory = await this.room.storage.list();
|
|
424
455
|
const tmpObject = root || {};
|
|
@@ -429,10 +460,10 @@ var Server = class {
|
|
|
429
460
|
dset2(tmpObject, key, value);
|
|
430
461
|
}
|
|
431
462
|
load(instance, tmpObject);
|
|
432
|
-
};
|
|
463
|
+
}, "loadMemory");
|
|
433
464
|
await loadMemory();
|
|
434
465
|
instance.$memoryAll = {};
|
|
435
|
-
const syncCb = (values) => {
|
|
466
|
+
const syncCb = /* @__PURE__ */ __name((values) => {
|
|
436
467
|
if (options.getMemoryAll) {
|
|
437
468
|
buildObject(values, instance.$memoryAll);
|
|
438
469
|
}
|
|
@@ -441,22 +472,20 @@ var Server = class {
|
|
|
441
472
|
return;
|
|
442
473
|
}
|
|
443
474
|
const packet = buildObject(values, instance.$memoryAll);
|
|
444
|
-
this.room.broadcast(
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
})
|
|
449
|
-
);
|
|
475
|
+
this.room.broadcast(JSON.stringify({
|
|
476
|
+
type: "sync",
|
|
477
|
+
value: packet
|
|
478
|
+
}));
|
|
450
479
|
values.clear();
|
|
451
|
-
};
|
|
452
|
-
const persistCb = async (values) => {
|
|
480
|
+
}, "syncCb");
|
|
481
|
+
const persistCb = /* @__PURE__ */ __name(async (values) => {
|
|
453
482
|
for (let path of values) {
|
|
454
483
|
const _instance = path == "." ? instance : getByPath(instance, path);
|
|
455
484
|
const itemValue = createStatesSnapshot(_instance);
|
|
456
485
|
await this.room.storage.put(path, itemValue);
|
|
457
486
|
}
|
|
458
487
|
values.clear();
|
|
459
|
-
};
|
|
488
|
+
}, "persistCb");
|
|
460
489
|
syncClass(instance, {
|
|
461
490
|
onSync: throttle(syncCb, instance["throttleSync"] ?? 500),
|
|
462
491
|
onPersist: throttle(persistCb, instance["throttleStorage"] ?? 2e3)
|
|
@@ -464,21 +493,21 @@ var Server = class {
|
|
|
464
493
|
return instance;
|
|
465
494
|
}
|
|
466
495
|
/**
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
496
|
+
* @method getSubRoom
|
|
497
|
+
* @private
|
|
498
|
+
* @async
|
|
499
|
+
* @param {Object} [options={}] - Options for getting the sub-room.
|
|
500
|
+
* @returns {Promise<Object>} The sub-room instance.
|
|
501
|
+
*
|
|
502
|
+
* @example
|
|
503
|
+
* ```typescript
|
|
504
|
+
* // This method is private and called internally
|
|
505
|
+
* async function internalGetSubRoom() {
|
|
506
|
+
* const subRoom = await this.getSubRoom();
|
|
507
|
+
* console.log("Sub-room retrieved:", subRoom);
|
|
508
|
+
* }
|
|
509
|
+
* ```
|
|
510
|
+
*/
|
|
482
511
|
async getSubRoom(options = {}) {
|
|
483
512
|
let subRoom;
|
|
484
513
|
if (this.isHibernate) {
|
|
@@ -489,20 +518,20 @@ var Server = class {
|
|
|
489
518
|
return subRoom;
|
|
490
519
|
}
|
|
491
520
|
/**
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
521
|
+
* @method getUsersProperty
|
|
522
|
+
* @private
|
|
523
|
+
* @param {Object} subRoom - The sub-room instance.
|
|
524
|
+
* @returns {Object|null} The users property of the sub-room, or null if not found.
|
|
525
|
+
*
|
|
526
|
+
* @example
|
|
527
|
+
* ```typescript
|
|
528
|
+
* // This method is private and called internally
|
|
529
|
+
* function internalGetUsers(subRoom) {
|
|
530
|
+
* const users = this.getUsersProperty(subRoom);
|
|
531
|
+
* console.log("Users:", users);
|
|
532
|
+
* }
|
|
533
|
+
* ```
|
|
534
|
+
*/
|
|
506
535
|
getUsersProperty(subRoom) {
|
|
507
536
|
const meta = subRoom.constructor["_propertyMetadata"];
|
|
508
537
|
const propId = meta?.get("users");
|
|
@@ -512,21 +541,21 @@ var Server = class {
|
|
|
512
541
|
return null;
|
|
513
542
|
}
|
|
514
543
|
/**
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
544
|
+
* @method onConnect
|
|
545
|
+
* @async
|
|
546
|
+
* @param {Party.Connection} conn - The connection object for the new user.
|
|
547
|
+
* @param {Party.ConnectionContext} ctx - The context of the connection.
|
|
548
|
+
* @description Handles a new user connection, creates a user object, and sends initial sync data.
|
|
549
|
+
* @returns {Promise<void>}
|
|
550
|
+
*
|
|
551
|
+
* @example
|
|
552
|
+
* ```typescript
|
|
553
|
+
* server.onConnect = async (conn, ctx) => {
|
|
554
|
+
* await server.onConnect(conn, ctx);
|
|
555
|
+
* console.log("New user connected:", conn.id);
|
|
556
|
+
* };
|
|
557
|
+
* ```
|
|
558
|
+
*/
|
|
530
559
|
async onConnect(conn, ctx) {
|
|
531
560
|
const subRoom = await this.getSubRoom({
|
|
532
561
|
getMemoryAll: true
|
|
@@ -540,33 +569,33 @@ var Server = class {
|
|
|
540
569
|
signal()[publicId] = user;
|
|
541
570
|
}
|
|
542
571
|
await awaitReturn(subRoom["onJoin"]?.(user, conn, ctx));
|
|
543
|
-
conn.setState({
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
}
|
|
552
|
-
);
|
|
572
|
+
conn.setState({
|
|
573
|
+
publicId
|
|
574
|
+
});
|
|
575
|
+
conn.send(JSON.stringify({
|
|
576
|
+
type: "sync",
|
|
577
|
+
value: {
|
|
578
|
+
pId: publicId,
|
|
579
|
+
...subRoom.$memoryAll
|
|
580
|
+
}
|
|
581
|
+
}));
|
|
553
582
|
}
|
|
554
583
|
/**
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
584
|
+
* @method onMessage
|
|
585
|
+
* @async
|
|
586
|
+
* @param {string} message - The message received from a user.
|
|
587
|
+
* @param {Party.Connection} sender - The connection object of the sender.
|
|
588
|
+
* @description Processes incoming messages and triggers corresponding actions in the sub-room.
|
|
589
|
+
* @returns {Promise<void>}
|
|
590
|
+
*
|
|
591
|
+
* @example
|
|
592
|
+
* ```typescript
|
|
593
|
+
* server.onMessage = async (message, sender) => {
|
|
594
|
+
* await server.onMessage(message, sender);
|
|
595
|
+
* console.log("Message processed from:", sender.id);
|
|
596
|
+
* };
|
|
597
|
+
* ```
|
|
598
|
+
*/
|
|
570
599
|
async onMessage(message, sender) {
|
|
571
600
|
let json;
|
|
572
601
|
try {
|
|
@@ -587,34 +616,30 @@ var Server = class {
|
|
|
587
616
|
const actionName = actions.get(result.data.action);
|
|
588
617
|
if (actionName) {
|
|
589
618
|
if (actionName.bodyValidation) {
|
|
590
|
-
const bodyResult = actionName.bodyValidation.safeParse(
|
|
591
|
-
result.data.value
|
|
592
|
-
);
|
|
619
|
+
const bodyResult = actionName.bodyValidation.safeParse(result.data.value);
|
|
593
620
|
if (!bodyResult.success) {
|
|
594
621
|
return;
|
|
595
622
|
}
|
|
596
623
|
}
|
|
597
|
-
await awaitReturn(
|
|
598
|
-
subRoom[actionName.key](user, result.data.value, sender)
|
|
599
|
-
);
|
|
624
|
+
await awaitReturn(subRoom[actionName.key](user, result.data.value, sender));
|
|
600
625
|
}
|
|
601
626
|
}
|
|
602
627
|
}
|
|
603
628
|
/**
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
629
|
+
* @method onClose
|
|
630
|
+
* @async
|
|
631
|
+
* @param {Party.Connection} conn - The connection object of the disconnecting user.
|
|
632
|
+
* @description Handles user disconnection, removing them from the room and triggering the onLeave event.
|
|
633
|
+
* @returns {Promise<void>}
|
|
634
|
+
*
|
|
635
|
+
* @example
|
|
636
|
+
* ```typescript
|
|
637
|
+
* server.onClose = async (conn) => {
|
|
638
|
+
* await server.onClose(conn);
|
|
639
|
+
* console.log("User disconnected:", conn.id);
|
|
640
|
+
* };
|
|
641
|
+
* ```
|
|
642
|
+
*/
|
|
618
643
|
async onClose(conn) {
|
|
619
644
|
const subRoom = await this.getSubRoom();
|
|
620
645
|
const signal = this.getUsersProperty(subRoom);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/decorators.ts","../../sync/src/utils.ts","../src/mock.ts","../src/server.ts","../../sync/src/core.ts","../../sync/src/load.ts","../src/utils.ts"],"sourcesContent":["export function Action(name: string, bodyValidation?) {\n return function (target: any, propertyKey: string) {\n if (!target.constructor._actionMetadata) {\n target.constructor._actionMetadata = new Map();\n }\n target.constructor._actionMetadata.set(name, {\n key: propertyKey,\n bodyValidation,\n });\n };\n}\n\nexport interface RoomOptions {\n path: string;\n maxUsers?: number;\n throttleStorage?: number;\n throttleSync?: number;\n hibernate?: boolean;\n}\n\nexport function Room(options: RoomOptions) {\n return function (target: any) {\n target.path = options.path;\n target.maxUsers = options.maxUsers;\n target.throttleStorage = options.throttleStorage;\n target.throttleSync = options.throttleSync;\n };\n}\n","/**\n * Checks if the given value is a function.\n *\n * @param {unknown} val - The value to check.\n * @returns {boolean} - True if the value is a function, false otherwise.\n * @example\n * isFunction(function() {}); // true\n * isFunction(() => {}); // true\n * isFunction(123); // false\n */\nexport function isFunction(val: unknown): boolean {\n return {}.toString.call(val) === \"[object Function]\";\n}\n\n/**\n * Checks if the given object is a class.\n *\n * @param {any} obj - The object to check.\n * @returns {boolean} - True if the object is a class, false otherwise.\n * @example\n * class MyClass {}\n * isClass(MyClass); // true\n * isClass(() => {}); // false\n */\nexport function isClass(obj: any): boolean {\n return (\n typeof obj === \"function\" &&\n obj.prototype &&\n obj.prototype.constructor === obj\n );\n}\n\n/**\n * Checks if the given item is an object.\n *\n * @param {any} item - The item to check.\n * @returns {boolean} - True if the item is an object, false otherwise.\n * @example\n * isObject({}); // true\n * isObject(null); // false\n * isObject([]); // false\n */\nexport const isObject = (item: any): boolean =>\n item && typeof item === \"object\" && !Array.isArray(item) && item !== null;\n\n/**\n * Checks if the given value is an instance of a class.\n *\n * @param {unknown} value - The value to check.\n * @returns {boolean} - True if the value is an instance of a class, false otherwise.\n * @example\n * class MyClass {}\n * const instance = new MyClass();\n * isInstanceOfClass(instance); // true\n * isInstanceOfClass({}); // false\n */\nexport function isInstanceOfClass(value: unknown): boolean {\n if (\n value === null ||\n typeof value !== \"object\" ||\n value === undefined ||\n Array.isArray(value)\n ) {\n return false;\n }\n return Object.getPrototypeOf(value) !== Object.prototype;\n}\n\nexport function generateShortUUID(): string {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n let uuid = '';\n for (let i = 0; i < 8; i++) {\n const randomIndex = Math.floor(Math.random() * chars.length);\n uuid += chars[randomIndex];\n }\n return uuid;\n}","import { generateShortUUID } from \"../../sync/src/utils\";\n\nclass MockPartySocket {\n private events: Map<string, Function> = new Map();\n id = generateShortUUID()\n \n addEventListener(event, cb) {\n this.events.set(event, cb);\n }\n\n removeEventListener(event, cb) {\n this.events.delete(event);\n }\n\n _trigger(event, data) {\n this.events.get(event)?.(data);\n }\n}\n\nclass MockStorage {\n private storage: Map<string, any> = new Map();\n \n async get(key: string) {\n return this.storage.get(key);\n }\n \n async put(key: string, value: any) {\n this.storage.set(key, value);\n }\n \n async list() {\n return this.storage\n }\n}\n\nclass MockPartyRoom {\n private clients: Map<string, MockPartySocket> = new Map();\n storage = new MockStorage();\n\n constructor(public id?: string) {\n this.id = id || generateShortUUID()\n }\n\n connection(client) {\n const socket = new MockPartySocket();\n this.clients.set(socket.id, client);\n client.id = socket.id;\n }\n\n broadcast(data: any) {\n this.clients.forEach((client) => {\n client._trigger('message', data);\n });\n }\n\n clear() {\n this.clients.clear();\n }\n}\n\nexport class MockConnection {\n state: any = {};\n\n setState(value: any) {\n this.state = value;\n }\n}\n\nexport const ServerIo = MockPartyRoom;\nexport const ClientIo = MockPartySocket;\n","import { dset } from \"dset\";\nimport z from \"zod\";\nimport {\n createStatesSnapshot,\n getByPath,\n load,\n syncClass,\n} from \"../../sync/src\";\nimport { generateShortUUID } from \"../../sync/src/utils\";\nimport type * as Party from \"./types/party\";\nimport {\n awaitReturn,\n buildObject,\n extractParams,\n isClass,\n throttle,\n} from \"./utils\";\n\nconst Message = z.object({\n action: z.string(),\n value: z.any(),\n});\n\ntype CreateRoomOptions = {\n getMemoryAll?: boolean;\n};\n\n/**\n * @class Server\n * @implements {Party.Server}\n * @description Represents a server that manages rooms and connections for a multiplayer game or application.\n * \n * @example\n * ```typescript\n * import { Room, Server, ServerIo } from \"@yourpackage/room\";\n * \n * @Room({ path: \"game\" })\n * class GameRoom {\n * // Room implementation\n * }\n * \n * class MyServer extends Server {\n * rooms = [GameRoom];\n * }\n * \n * const server = new MyServer(new ServerIo(\"game\"));\n * server.onStart();\n * ```\n */\nexport class Server implements Party.Server {\n subRoom = null;\n rooms: any[] = [];\n\n /**\n * @constructor\n * @param {Party.Room} room - The room object representing the current game or application instance.\n * \n * @example\n * ```typescript\n * const server = new MyServer(new ServerIo(\"game\"));\n * ```\n */\n constructor(readonly room: Party.Room) {}\n\n /**\n * @readonly\n * @property {boolean} isHibernate - Indicates whether the server is in hibernate mode.\n * \n * @example\n * ```typescript\n * if (!server.isHibernate) {\n * console.log(\"Server is active\");\n * }\n * ```\n */\n get isHibernate(): boolean {\n return !!this[\"options\"]?.hibernate;\n }\n\n /**\n * @method onStart\n * @async\n * @description Initializes the server and creates the initial room if not in hibernate mode.\n * @returns {Promise<void>}\n * \n * @example\n * ```typescript\n * async function initServer() {\n * await server.onStart();\n * console.log(\"Server started\");\n * }\n * ```\n */\n\n async onStart() {\n // Only create a room if not in hibernate mode\n // This prevents unnecessary resource allocation for inactive rooms\n if (!this.isHibernate) {\n this.subRoom = await this.createRoom();\n }\n }\n\n /**\n * @method createRoom\n * @private\n * @async\n * @param {CreateRoomOptions} [options={}] - Options for creating the room.\n * @returns {Promise<Object>} The created room instance.\n * @throws {Error} If no matching room is found.\n * \n * @example\n * ```typescript\n * // This method is private and called internally\n * async function internalCreateRoom() {\n * const room = await this.createRoom({ getMemoryAll: true });\n * console.log(\"Room created:\", room);\n * }\n * ```\n */\n private async createRoom(options: CreateRoomOptions = {}) {\n let instance\n let init = true\n\n // Find the appropriate room based on the current room ID\n for (let room of this.rooms) {\n const params = extractParams(room.path, this.room.id);\n if (params) {\n instance = new room(this.room, params);\n break;\n }\n }\n\n if (!instance) {\n throw new Error(\"Room not found\");\n }\n\n // Load the room's memory from storage\n // This ensures persistence across server restarts\n const loadMemory = async () => {\n const root = await this.room.storage.get(\".\");\n const memory = await this.room.storage.list();\n const tmpObject: any = root || {};\n for (let [key, value] of memory) {\n if (key == \".\") {\n continue;\n }\n dset(tmpObject, key, value);\n }\n load(instance, tmpObject);\n };\n\n await loadMemory();\n\n instance.$memoryAll = {}\n\n // Sync callback: Broadcast changes to all clients\n const syncCb = (values) => {\n if (options.getMemoryAll) {\n buildObject(values, instance.$memoryAll);\n }\n if (init && this.isHibernate) {\n init = false;\n return;\n }\n const packet = buildObject(values, instance.$memoryAll);\n this.room.broadcast(\n JSON.stringify({\n type: \"sync\",\n value: packet,\n })\n );\n values.clear();\n }\n\n // Persist callback: Save changes to storage\n const persistCb = async (values) => {\n for (let path of values) {\n const _instance =\n path == \".\" ? instance : getByPath(instance, path);\n const itemValue = createStatesSnapshot(_instance);\n await this.room.storage.put(path, itemValue);\n }\n values.clear();\n }\n\n // Set up syncing and persistence with throttling to optimize performance\n syncClass(instance, {\n onSync: throttle(syncCb, instance[\"throttleSync\"] ?? 500),\n onPersist: throttle(persistCb, instance[\"throttleStorage\"] ?? 2000),\n });\n\n return instance\n }\n\n /**\n * @method getSubRoom\n * @private\n * @async\n * @param {Object} [options={}] - Options for getting the sub-room.\n * @returns {Promise<Object>} The sub-room instance.\n * \n * @example\n * ```typescript\n * // This method is private and called internally\n * async function internalGetSubRoom() {\n * const subRoom = await this.getSubRoom();\n * console.log(\"Sub-room retrieved:\", subRoom);\n * }\n * ```\n */\n private async getSubRoom(options = {}) {\n let subRoom\n if (this.isHibernate) {\n subRoom = await this.createRoom(options)\n }\n else {\n subRoom = this.subRoom\n }\n return subRoom\n }\n\n /**\n * @method getUsersProperty\n * @private\n * @param {Object} subRoom - The sub-room instance.\n * @returns {Object|null} The users property of the sub-room, or null if not found.\n * \n * @example\n * ```typescript\n * // This method is private and called internally\n * function internalGetUsers(subRoom) {\n * const users = this.getUsersProperty(subRoom);\n * console.log(\"Users:\", users);\n * }\n * ```\n */\n\n private getUsersProperty(subRoom) {\n const meta = subRoom.constructor[\"_propertyMetadata\"];\n const propId = meta?.get(\"users\");\n if (propId) {\n return subRoom[propId];\n }\n return null;\n }\n\n /**\n * @method onConnect\n * @async\n * @param {Party.Connection} conn - The connection object for the new user.\n * @param {Party.ConnectionContext} ctx - The context of the connection.\n * @description Handles a new user connection, creates a user object, and sends initial sync data.\n * @returns {Promise<void>}\n * \n * @example\n * ```typescript\n * server.onConnect = async (conn, ctx) => {\n * await server.onConnect(conn, ctx);\n * console.log(\"New user connected:\", conn.id);\n * };\n * ```\n */\n async onConnect(conn: Party.Connection, ctx: Party.ConnectionContext) {\n const subRoom = await this.getSubRoom({\n getMemoryAll: true,\n })\n // Generate a unique public ID for the user\n const publicId = generateShortUUID()\n let user = null;\n const signal = this.getUsersProperty(subRoom);\n if (signal) {\n const { classType } = signal.options;\n // Create a new user instance based on the defined class type\n user = isClass(classType) ? new classType() : classType(conn, ctx);\n signal()[publicId] = user;\n }\n // Call the room's onJoin method if it exists\n await awaitReturn(subRoom[\"onJoin\"]?.(user, conn, ctx));\n conn.setState({ publicId });\n // Send initial sync data to the new connection\n conn.send(\n JSON.stringify({\n type: \"sync\",\n value: {\n pId: publicId,\n ...subRoom.$memoryAll,\n },\n })\n );\n }\n\n /**\n * @method onMessage\n * @async\n * @param {string} message - The message received from a user.\n * @param {Party.Connection} sender - The connection object of the sender.\n * @description Processes incoming messages and triggers corresponding actions in the sub-room.\n * @returns {Promise<void>}\n * \n * @example\n * ```typescript\n * server.onMessage = async (message, sender) => {\n * await server.onMessage(message, sender);\n * console.log(\"Message processed from:\", sender.id);\n * };\n * ```\n */\n\n async onMessage(message: string, sender: Party.Connection) {\n let json\n try {\n json = JSON.parse(message)\n }\n catch (e) {\n return;\n }\n // Validate incoming messages\n const result = Message.safeParse(json);\n if (!result.success) {\n return;\n }\n const subRoom = await this.getSubRoom()\n const actions = subRoom.constructor[\"_actionMetadata\"];\n if (actions) {\n const signal = this.getUsersProperty(subRoom);\n const { publicId } = sender.state as any;\n const user = signal?.()[publicId];\n const actionName = actions.get(result.data.action);\n if (actionName) {\n // Validate action body if a validation schema is defined\n if (actionName.bodyValidation) {\n const bodyResult = actionName.bodyValidation.safeParse(\n result.data.value\n );\n if (!bodyResult.success) {\n return;\n }\n }\n // Execute the action\n await awaitReturn(\n subRoom[actionName.key](user, result.data.value, sender)\n );\n }\n }\n }\n\n /**\n * @method onClose\n * @async\n * @param {Party.Connection} conn - The connection object of the disconnecting user.\n * @description Handles user disconnection, removing them from the room and triggering the onLeave event.\n * @returns {Promise<void>}\n * \n * @example\n * ```typescript\n * server.onClose = async (conn) => {\n * await server.onClose(conn);\n * console.log(\"User disconnected:\", conn.id);\n * };\n * ```\n */\n async onClose(conn: Party.Connection) {\n const subRoom = await this.getSubRoom()\n const signal = this.getUsersProperty(subRoom);\n const { publicId } = conn.state as any;\n const user = signal?.()[publicId];\n // Call the room's onLeave method if it exists\n await awaitReturn(subRoom[\"onLeave\"]?.(user, conn));\n if (signal) {\n // Remove the user from the room\n delete signal()[publicId];\n }\n }\n}\n","import {\n ArraySubject,\n ObjectSubject,\n isSignal,\n type WritableSignal,\n} from \"@signe/reactive\";\nimport { isInstanceOfClass, isObject } from \"./utils\";\n\ninterface SyncOptions {\n onSync?: (value: Map<string, any>) => void;\n onPersist?: (value: Set<string>) => void;\n}\n\ninterface TypeOptions {\n syncToClient?: boolean;\n persist?: boolean;\n classType?: any;\n}\n\n/**\n * Synchronizes an instance by adding `$valuesChanges` methods for state management.\n *\n * This function initializes a cache for syncing and persisting values. It adds methods to the instance\n * to set values, mark values for persistence, and check and retrieve values from the cache.\n * Optionally, callbacks can be provided to handle synchronization and persistence events.\n *\n * @param {Record<string, any>} instance - The instance to be synchronized.\n * @param {SyncOptions} [options={}] - Optional synchronization options.\n * @param {Function} [options.onSync] - Callback function to be called on value sync with the current cache.\n * @param {Function} [options.onPersist] - Callback function to be called on value persistence with the current cache.\n *\n * @example\n * class TestClass {\n * @sync() count = signal(0);\n * @sync() text = signal('hello');\n * }\n * const instance = new TestClass();\n * syncClass(instance, {\n * onSync: (cache) => console.log('Sync cache:', cache),\n * onPersist: (cache) => console.log('Persist cache:', cache),\n * });\n */\nexport const syncClass = (instance: any, options: SyncOptions = {}) => {\n const cacheSync = new Map();\n const cachePersist = new Set<string>();\n instance.$valuesChanges = {\n set: (path: string, value: any) => {\n cacheSync.set(path, value);\n options.onSync?.(cacheSync);\n },\n setPersist: (path: string) => {\n if (path == \"\") path = \".\";\n cachePersist.add(path);\n options.onPersist?.(cachePersist);\n },\n has: (path: string) => {\n return cacheSync.has(path);\n },\n get: (path: string) => {\n return cacheSync.get(path);\n },\n };\n createSyncClass(instance);\n};\n\n/**\n * Creates a snapshot of the current state of an instance's signals.\n *\n * This function iterates over the signals stored in the instance's $snapshot property.\n * If a signal's value is not an object or array and the signal's persist option is true or undefined,\n * it adds the signal's value to the returned snapshot object.\n *\n * @param {Record<string, any>} instance - The instance containing the $snapshot map of signals.\n * @returns {Record<string, any>} - An object representing the persisted snapshot of the instance's state.\n *\n * @example\n * ```typescript\n * class TestClass {\n * @sync() count = signal(0);\n * @sync() text = signal('hello');\n * }\n * const instance = new TestClass();\n * syncClass(instance);\n * const snapshot = createStatesSnapshot(instance);\n * console.log(snapshot); // { count: 0, text: 'hello' }\n * ```\n */\nexport function createStatesSnapshot(instance: Record<string, any>): Record<string, any> {\n let persistObject: any = {};\n if (instance.$snapshot) {\n for (const key of instance.$snapshot.keys()) {\n const signal = instance.$snapshot.get(key);\n const persist = signal.options.persist ?? true;\n let value = signal();\n if (isObject(value) || Array.isArray(value)) {\n break;\n }\n if (persist) {\n persistObject[key] = value;\n }\n }\n }\n return persistObject;\n}\n\nexport function setMetadata(target: any, key: string, value: any) {\n const meta = target.constructor._propertyMetadata;\n const propId = meta?.get(key);\n if (propId) {\n if (isSignal(target[propId])) {\n target[propId].set(value);\n } else {\n target[propId] = value;\n }\n }\n}\n\nexport const createSyncClass = (\n currentClass: any,\n parentKey: any = null,\n parentClass = null,\n path = \"\"\n) => {\n currentClass.$path = path;\n if (parentClass) {\n currentClass.$valuesChanges = parentClass.$valuesChanges;\n }\n if (parentKey) {\n setMetadata(currentClass, \"id\", parentKey);\n }\n if (currentClass.$snapshot) {\n for (const key of currentClass.$snapshot.keys()) {\n const signal = currentClass.$snapshot.get(key);\n const syncToClient = signal.options.syncToClient ?? true;\n const persist = signal.options.persist ?? true;\n let value = signal();\n if (isObject(value) || Array.isArray(value)) {\n value = { ...value };\n }\n const newPath = (path ? path + \".\" : \"\") + key;\n if (syncToClient) {\n currentClass.$valuesChanges.set(newPath, value);\n }\n if (persist) {\n if (parentClass) currentClass.$valuesChanges.setPersist(path);\n }\n }\n }\n};\n\nexport const type = (\n _signal: any,\n path: string,\n options: TypeOptions = {},\n currentInstance: any\n): WritableSignal<any> => {\n const syncToClient = options.syncToClient ?? true;\n const persist = options.persist ?? true;\n let init = true;\n _signal.options = options;\n _signal.observable.subscribe((value) => {\n const check = currentInstance.$valuesChanges;\n\n function savePath(propPath, value) {\n if (syncToClient) check.set(propPath, value);\n if (persist) {\n check.setPersist(currentInstance.$path);\n }\n }\n\n if (init) {\n init = false;\n return;\n }\n if (currentInstance.$path !== undefined) {\n const propPath =\n (currentInstance.$path ? currentInstance.$path + \".\" : \"\") + path;\n if (_signal._subject instanceof ObjectSubject) {\n const newPath =\n (currentInstance.$path ? currentInstance.$path + \".\" : \"\") +\n path +\n \".\" +\n value.key;\n\n if (value.type == \"add\") {\n if (isInstanceOfClass(value.value)) {\n createSyncClass(value.value, value.key, currentInstance, newPath);\n } else {\n savePath(newPath, value.value);\n }\n } else if (value.type == \"update\") {\n if (isObject(value.value) || Array.isArray(value.value)) {\n createSyncClass(value.value, value.key, currentInstance, newPath);\n } else {\n savePath(newPath, value.value);\n }\n } else if (value.type == \"remove\") {\n savePath(newPath, \"$delete\");\n }\n } else if (_signal._subject instanceof ArraySubject) {\n const newPath = propPath + \".\" + value.index;\n const firstItem = value.items[0];\n if (value.type == \"add\") {\n if (isInstanceOfClass(firstItem)) {\n createSyncClass(firstItem, value.key, currentInstance, newPath);\n } else {\n savePath(newPath, firstItem);\n }\n } else if (value.type == \"update\") {\n if (isObject(firstItem) || Array.isArray(firstItem)) {\n createSyncClass(firstItem, value.key, currentInstance, newPath);\n } else {\n savePath(newPath, firstItem);\n }\n } else if (value.type == \"remove\") {\n savePath(newPath, \"$delete\");\n }\n } else {\n savePath(propPath, value);\n }\n }\n });\n\n if (!currentInstance.$snapshot) {\n currentInstance.$snapshot = new Map();\n }\n\n currentInstance.$snapshot.set(path, _signal);\n\n return _signal;\n};\n","import { isSignal } from \"@signe/reactive\";\nimport { setMetadata } from \"./core\";\nimport { isClass } from \"./utils\";\n\n/**\n * Loads values into the root instance by paths or from an object.\n * \n * @param {object} rootInstance - The instance into which values will be loaded.\n * @param {object} values - The values to load, either as paths or an object.\n * @param {boolean} [valueIsObject=false] - If true, `values` is treated as an object.\n * @example\n * // Using paths:\n * load(instance, { 'position.x': 10, 'position.y': 20 });\n * \n * // Using an object:\n * load(instance, { position: { x: 10, y: 20 } }, true);\n */\nexport function load(rootInstance: any, values: { [path: string]: any }): void;\nexport function load(\n rootInstance: any,\n values: object,\n valueIsObject: true\n): void;\nexport function load(\n rootInstance: any,\n values: { [path: string]: any } | object,\n valueIsObject?: boolean\n) {\n if (valueIsObject) {\n loadFromObject(rootInstance, values);\n } else {\n loadFromPaths(rootInstance, values);\n }\n}\n\n/**\n * Loads values into the root instance using paths.\n * \n * @param {object} rootInstance - The instance into which values will be loaded.\n * @param {object} values - The values to load, with keys as paths.\n * @example\n * loadFromPaths(instance, { 'position.x': 10, 'position.y': 20 });\n */\nfunction loadFromPaths(rootInstance: any, values: { [path: string]: any }) {\n for (const [path, value] of Object.entries(values)) {\n const parts = path.split(\".\");\n loadValue(rootInstance, parts, value);\n }\n}\n\n/**\n * Recursively loads values from an object into the root instance.\n * \n * @param {object} rootInstance - The instance into which values will be loaded.\n * @param {object} values - The values to load.\n * @param {string} [currentPath=\"\"] - The current path in the recursion.\n * @example\n * loadFromObject(instance, { position: { x: 10, y: 20 } });\n */\nfunction loadFromObject(\n rootInstance: any,\n values: object,\n currentPath: string = \"\"\n) {\n for (const [key, value] of Object.entries(values)) {\n const newPath = currentPath ? `${currentPath}.${key}` : key;\n if (typeof value === \"object\" && !Array.isArray(value)) {\n loadFromObject(rootInstance, value, newPath);\n } else {\n const parts = newPath.split(\".\");\n loadValue(rootInstance, parts, value);\n }\n }\n}\n\n/**\n * Sets a value in the root instance by navigating through the path parts.\n * \n * @param {object} rootInstance - The instance into which the value will be set.\n * @param {string[]} parts - The parts of the path.\n * @param {any} value - The value to set.\n * @example\n * loadValue(instance, ['position', 'x'], 10);\n */\nfunction loadValue(rootInstance: any, parts: string[], value: any) {\n let current: any = rootInstance;\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n\n if (i === parts.length - 1) {\n if (value == '$delete') {\n if (isSignal(current)) {\n current = current();\n }\n Reflect.deleteProperty(current, part);\n }\n else if (current[part]?._subject) {\n current[part].set(value);\n }\n } else {\n if (isSignal(current)) {\n current = current();\n }\n const currentValue = current[part];\n if (currentValue === undefined) {\n const parentInstance = getByPath(\n rootInstance,\n parts.slice(0, i).join(\".\")\n );\n const classType = parentInstance?.options?.classType;\n if (classType) {\n current[part] = !isClass(classType) ? classType(part) : new classType();\n setMetadata(current[part], 'id', part)\n } else {\n current[part] = {};\n }\n }\n current = current[part];\n }\n }\n}\n\n/**\n * Retrieves a value from the root instance by a path.\n * \n * @param {object} root - The root instance.\n * @param {string} path - The path to the value.\n * @returns {any} - The value at the specified path.\n * @example\n * const value = getByPath(instance, 'position.x');\n */\nexport function getByPath(root: any, path: string) {\n const parts = path.split(\".\");\n let current = root;\n for (const part of parts) {\n if (isSignal(current)) {\n current = current();\n }\n if (current[part]) {\n current = current[part];\n } else {\n return undefined;\n }\n }\n return current;\n}\n","import { dset } from \"dset\";\n\n/**\n * Checks if a value is a Promise.\n *\n * @param {unknown} value - The value to check.\n * @returns {boolean} - Returns true if the value is a Promise, otherwise false.\n *\n * @example\n * isPromise(Promise.resolve()); // true\n * isPromise(42); // false\n */\nexport function isPromise(value: unknown): value is Promise<any> {\n return value instanceof Promise;\n}\n\n/**\n * Awaits the given value if it is a Promise, otherwise returns the value directly.\n *\n * @param {unknown} val - The value to await or return.\n * @returns {Promise<any>} - Returns a Promise that resolves to the value.\n *\n * @example\n * awaitReturn(Promise.resolve(42)); // 42\n * awaitReturn(42); // 42\n */\nexport async function awaitReturn(val: unknown): Promise<any> {\n return isPromise(val) ? await val : val;\n}\n\n/**\n * Checks if a value is a class.\n *\n * @param {unknown} obj - The value to check.\n * @returns {boolean} - Returns true if the value is a class, otherwise false.\n *\n * @example\n * class MyClass {}\n * isClass(MyClass); // true\n * isClass(() => {}); // false\n */\nexport function isClass(obj: unknown): boolean {\n return (\n typeof obj === \"function\" &&\n obj.prototype &&\n obj.prototype.constructor === obj\n );\n}\n\n\n/**\n * Creates a throttled function that only invokes the provided function at most once per every wait milliseconds.\n *\n * The throttled function comes with a cancel method to cancel delayed invocations.\n * If the throttled function is invoked more than once during the wait timeout,\n * it will call the provided function with the latest arguments.\n *\n * @template F - The type of the function to throttle.\n * @param {F} func - The function to throttle.\n * @param {number} wait - The number of milliseconds to throttle invocations to.\n * @returns {(...args: Parameters<F>) => void} - Returns the new throttled function.\n *\n * @example\n * const log = throttle((message) => console.log(message), 1000);\n * log(\"Hello\"); // Will log \"Hello\" immediately\n * log(\"World\"); // Will log \"World\" after 1 second, if no other calls to log() are made within the 1 second.\n */\nexport function throttle<F extends (...args: any[]) => any>(\n func: F,\n wait: number\n): (...args: Parameters<F>) => void {\n let timeout: ReturnType<typeof setTimeout> | null = null;\n let lastArgs: Parameters<F> | null = null;\n\n return function (...args: Parameters<F>) {\n if (!timeout) {\n func(...args);\n timeout = setTimeout(() => {\n if (lastArgs) {\n func(...lastArgs);\n lastArgs = null;\n }\n timeout = null;\n }, wait);\n } else {\n lastArgs = args;\n }\n };\n}\n\n/**\n * Extracts parameters from a given string based on a specified pattern.\n *\n * The pattern can include placeholders in the form of {paramName}, which will be\n * extracted from the input string if they match.\n *\n * @param {string} pattern - The pattern containing placeholders.\n * @param {string} str - The string to extract parameters from.\n * @returns {{ [key: string]: string } | null} - An object containing the extracted parameters,\n * or null if the string does not match the pattern.\n *\n * @example\n * // returns { id: '123' }\n * extractParams('game-{id}', 'game-123');\n *\n * @example\n * // returns { foo: 'abc', bar: 'xyz' }\n * extractParams('test-{foo}-{bar}', 'test-abc-xyz');\n *\n */\nexport function extractParams(\n pattern: string,\n str: string\n): { [key: string]: string } | null {\n // Replace placeholders in the pattern with named capture groups\n const regexPattern = pattern.replace(/{(\\w+)}/g, \"(?<$1>[\\\\w-]+)\");\n\n // Create a strict regular expression from the pattern\n const regex = new RegExp(`^${regexPattern}$`);\n const match = regex.exec(str);\n\n // If a match is found and groups are present, return the captured groups\n if (match && match.groups) {\n return match.groups;\n } else if (pattern === str) {\n // If the pattern exactly matches the string, return an empty object\n return {};\n } else {\n // Otherwise, return null\n return null;\n }\n}\n\n/**\n * Removes a property from an object based on a dot-separated key string or an array of keys.\n *\n * The function modifies the original object by deleting the specified property.\n * It safely handles dangerous keys like __proto__, constructor, and prototype.\n *\n * @param {Record<string, any>} obj - The object from which to remove the property.\n * @param {string | string[]} keys - The key(s) specifying the property to remove. Can be a dot-separated string or an array of strings.\n *\n * @example\n * const obj = { a: { b: { c: 3 } } };\n * dremove(obj, 'a.b.c');\n * // obj is now { a: { b: {} } }\n *\n * @example\n * const obj = { a: 1, b: 2 };\n * dremove(obj, 'a');\n * // obj is now { b: 2 }\n *\n * @example\n * const obj = { a: { b: { c: 3 } } };\n * dremove(obj, ['a', 'b', 'c']);\n * // obj is now { a: { b: {} } }\n */\nexport function dremove(\n obj: Record<string, any>,\n keys: string | string[]\n): void {\n // If keys is a string, convert it to an array using the \".\" separator\n if (typeof keys === \"string\") {\n keys = keys.split(\".\");\n }\n\n let i = 0;\n const l = keys.length;\n let t = obj;\n let k;\n\n while (i < l - 1) {\n k = keys[i++];\n if (k === \"__proto__\" || k === \"constructor\" || k === \"prototype\") return; // Avoid dangerous keys\n if (typeof t[k] !== \"object\" || t[k] === null) return; // If the object doesn't exist, stop\n t = t[k];\n }\n\n k = keys[i];\n if (\n t &&\n typeof t === \"object\" &&\n !(k === \"__proto__\" || k === \"constructor\" || k === \"prototype\")\n ) {\n delete t[k];\n }\n}\n\n/**\n * Builds an object from a map of values and updates the provided memory object.\n *\n * For each key-value pair in the map, this function sets the value at the given path in the `memoryObj`.\n * If the value is \"$delete\", it removes the corresponding path from `allMemory`.\n *\n * @param {Map<string, any>} valuesMap - A map where the keys are paths and the values are the values to set at those paths.\n * @param {Record<string, any>} allMemory - The object to update based on the values in the map.\n * @returns {Record<string, any>} - The built memory object with the applied values from the map.\n *\n * @example\n * const valuesMap = new Map();\n * valuesMap.set('a.b.c', 1);\n * valuesMap.set('x.y.z', '$delete');\n * const allMemory = { x: { y: { z: 2 } } };\n * const result = buildObject(valuesMap, allMemory);\n * // result is { a: { b: { c: 1 } }, x: { y: { z: '$delete' } } }\n * // allMemory is { a: { b: { c: 1 } }, x: { y: {} } }\n */\nexport function buildObject(valuesMap: Map<string, any>, allMemory: Record<string, any>): Record<string, any> {\n let memoryObj = {};\n for (let path of valuesMap.keys()) {\n const value = valuesMap.get(path);\n dset(memoryObj, path, value);\n if (value === \"$delete\") {\n dremove(allMemory, path);\n } else {\n dset(allMemory, path, value);\n }\n }\n return memoryObj;\n}"],"mappings":"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","names":["dset","isSignal","isSignal","isClass","dset","isClass"]}
|
|
1
|
+
{"version":3,"sources":["../src/decorators.ts","../../sync/src/utils.ts","../src/mock.ts","../src/server.ts","../../sync/src/core.ts","../../sync/src/load.ts","../src/utils.ts"],"sourcesContent":["export function Action(name: string, bodyValidation?) {\n return function (target: any, propertyKey: string) {\n if (!target.constructor._actionMetadata) {\n target.constructor._actionMetadata = new Map();\n }\n target.constructor._actionMetadata.set(name, {\n key: propertyKey,\n bodyValidation,\n });\n };\n}\n\nexport interface RoomOptions {\n path: string;\n maxUsers?: number;\n throttleStorage?: number;\n throttleSync?: number;\n hibernate?: boolean;\n}\n\nexport function Room(options: RoomOptions) {\n return function (target: any) {\n target.path = options.path;\n target.maxUsers = options.maxUsers;\n target.throttleStorage = options.throttleStorage;\n target.throttleSync = options.throttleSync;\n };\n}\n","/**\n * Checks if the given value is a function.\n *\n * @param {unknown} val - The value to check.\n * @returns {boolean} - True if the value is a function, false otherwise.\n * @example\n * isFunction(function() {}); // true\n * isFunction(() => {}); // true\n * isFunction(123); // false\n */\nexport function isFunction(val: unknown): boolean {\n return {}.toString.call(val) === \"[object Function]\";\n}\n\n/**\n * Checks if the given object is a class.\n *\n * @param {any} obj - The object to check.\n * @returns {boolean} - True if the object is a class, false otherwise.\n * @example\n * class MyClass {}\n * isClass(MyClass); // true\n * isClass(() => {}); // false\n */\nexport function isClass(obj: any): boolean {\n return (\n typeof obj === \"function\" &&\n obj.prototype &&\n obj.prototype.constructor === obj\n );\n}\n\n/**\n * Checks if the given item is an object.\n *\n * @param {any} item - The item to check.\n * @returns {boolean} - True if the item is an object, false otherwise.\n * @example\n * isObject({}); // true\n * isObject(null); // false\n * isObject([]); // false\n */\nexport const isObject = (item: any): boolean =>\n item && typeof item === \"object\" && !Array.isArray(item) && item !== null;\n\n/**\n * Checks if the given value is an instance of a class.\n *\n * @param {unknown} value - The value to check.\n * @returns {boolean} - True if the value is an instance of a class, false otherwise.\n * @example\n * class MyClass {}\n * const instance = new MyClass();\n * isInstanceOfClass(instance); // true\n * isInstanceOfClass({}); // false\n */\nexport function isInstanceOfClass(value: unknown): boolean {\n if (\n value === null ||\n typeof value !== \"object\" ||\n value === undefined ||\n Array.isArray(value)\n ) {\n return false;\n }\n return Object.getPrototypeOf(value) !== Object.prototype;\n}\n\nexport function generateShortUUID(): string {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\n let uuid = '';\n for (let i = 0; i < 8; i++) {\n const randomIndex = Math.floor(Math.random() * chars.length);\n uuid += chars[randomIndex];\n }\n return uuid;\n}","import { generateShortUUID } from \"../../sync/src/utils\";\n\nclass MockPartySocket {\n private events: Map<string, Function> = new Map();\n id = generateShortUUID()\n \n addEventListener(event, cb) {\n this.events.set(event, cb);\n }\n\n removeEventListener(event, cb) {\n this.events.delete(event);\n }\n\n _trigger(event, data) {\n this.events.get(event)?.(data);\n }\n}\n\nclass MockStorage {\n private storage: Map<string, any> = new Map();\n \n async get(key: string) {\n return this.storage.get(key);\n }\n \n async put(key: string, value: any) {\n this.storage.set(key, value);\n }\n \n async list() {\n return this.storage\n }\n}\n\nclass MockPartyRoom {\n private clients: Map<string, MockPartySocket> = new Map();\n storage = new MockStorage();\n\n constructor(public id?: string) {\n this.id = id || generateShortUUID()\n }\n\n connection(client) {\n const socket = new MockPartySocket();\n this.clients.set(socket.id, client);\n client.id = socket.id;\n }\n\n broadcast(data: any) {\n this.clients.forEach((client) => {\n client._trigger('message', data);\n });\n }\n\n clear() {\n this.clients.clear();\n }\n}\n\nexport class MockConnection {\n state: any = {};\n\n setState(value: any) {\n this.state = value;\n }\n}\n\nexport const ServerIo = MockPartyRoom;\nexport const ClientIo = MockPartySocket;\n","import { dset } from \"dset\";\nimport z from \"zod\";\nimport {\n createStatesSnapshot,\n getByPath,\n load,\n syncClass,\n} from \"../../sync/src\";\nimport { generateShortUUID } from \"../../sync/src/utils\";\nimport type * as Party from \"./types/party\";\nimport {\n awaitReturn,\n buildObject,\n extractParams,\n isClass,\n throttle,\n} from \"./utils\";\n\nconst Message = z.object({\n action: z.string(),\n value: z.any(),\n});\n\ntype CreateRoomOptions = {\n getMemoryAll?: boolean;\n};\n\n/**\n * @class Server\n * @implements {Party.Server}\n * @description Represents a server that manages rooms and connections for a multiplayer game or application.\n * \n * @example\n * ```typescript\n * import { Room, Server, ServerIo } from \"@yourpackage/room\";\n * \n * @Room({ path: \"game\" })\n * class GameRoom {\n * // Room implementation\n * }\n * \n * class MyServer extends Server {\n * rooms = [GameRoom];\n * }\n * \n * const server = new MyServer(new ServerIo(\"game\"));\n * server.onStart();\n * ```\n */\nexport class Server implements Party.Server {\n subRoom = null;\n rooms: any[] = [];\n\n /**\n * @constructor\n * @param {Party.Room} room - The room object representing the current game or application instance.\n * \n * @example\n * ```typescript\n * const server = new MyServer(new ServerIo(\"game\"));\n * ```\n */\n constructor(readonly room: Party.Room) {}\n\n /**\n * @readonly\n * @property {boolean} isHibernate - Indicates whether the server is in hibernate mode.\n * \n * @example\n * ```typescript\n * if (!server.isHibernate) {\n * console.log(\"Server is active\");\n * }\n * ```\n */\n get isHibernate(): boolean {\n return !!this[\"options\"]?.hibernate;\n }\n\n /**\n * @method onStart\n * @async\n * @description Initializes the server and creates the initial room if not in hibernate mode.\n * @returns {Promise<void>}\n * \n * @example\n * ```typescript\n * async function initServer() {\n * await server.onStart();\n * console.log(\"Server started\");\n * }\n * ```\n */\n\n async onStart() {\n // Only create a room if not in hibernate mode\n // This prevents unnecessary resource allocation for inactive rooms\n if (!this.isHibernate) {\n this.subRoom = await this.createRoom();\n }\n }\n\n /**\n * @method createRoom\n * @private\n * @async\n * @param {CreateRoomOptions} [options={}] - Options for creating the room.\n * @returns {Promise<Object>} The created room instance.\n * @throws {Error} If no matching room is found.\n * \n * @example\n * ```typescript\n * // This method is private and called internally\n * async function internalCreateRoom() {\n * const room = await this.createRoom({ getMemoryAll: true });\n * console.log(\"Room created:\", room);\n * }\n * ```\n */\n private async createRoom(options: CreateRoomOptions = {}) {\n let instance\n let init = true\n\n // Find the appropriate room based on the current room ID\n for (let room of this.rooms) {\n const params = extractParams(room.path, this.room.id);\n if (params) {\n instance = new room(this.room, params);\n break;\n }\n }\n\n if (!instance) {\n throw new Error(\"Room not found\");\n }\n\n // Load the room's memory from storage\n // This ensures persistence across server restarts\n const loadMemory = async () => {\n const root = await this.room.storage.get(\".\");\n const memory = await this.room.storage.list();\n const tmpObject: any = root || {};\n for (let [key, value] of memory) {\n if (key == \".\") {\n continue;\n }\n dset(tmpObject, key, value);\n }\n load(instance, tmpObject);\n };\n\n await loadMemory();\n\n instance.$memoryAll = {}\n\n // Sync callback: Broadcast changes to all clients\n const syncCb = (values) => {\n if (options.getMemoryAll) {\n buildObject(values, instance.$memoryAll);\n }\n if (init && this.isHibernate) {\n init = false;\n return;\n }\n const packet = buildObject(values, instance.$memoryAll);\n this.room.broadcast(\n JSON.stringify({\n type: \"sync\",\n value: packet,\n })\n );\n values.clear();\n }\n\n // Persist callback: Save changes to storage\n const persistCb = async (values) => {\n for (let path of values) {\n const _instance =\n path == \".\" ? instance : getByPath(instance, path);\n const itemValue = createStatesSnapshot(_instance);\n await this.room.storage.put(path, itemValue);\n }\n values.clear();\n }\n\n // Set up syncing and persistence with throttling to optimize performance\n syncClass(instance, {\n onSync: throttle(syncCb, instance[\"throttleSync\"] ?? 500),\n onPersist: throttle(persistCb, instance[\"throttleStorage\"] ?? 2000),\n });\n\n return instance\n }\n\n /**\n * @method getSubRoom\n * @private\n * @async\n * @param {Object} [options={}] - Options for getting the sub-room.\n * @returns {Promise<Object>} The sub-room instance.\n * \n * @example\n * ```typescript\n * // This method is private and called internally\n * async function internalGetSubRoom() {\n * const subRoom = await this.getSubRoom();\n * console.log(\"Sub-room retrieved:\", subRoom);\n * }\n * ```\n */\n private async getSubRoom(options = {}) {\n let subRoom\n if (this.isHibernate) {\n subRoom = await this.createRoom(options)\n }\n else {\n subRoom = this.subRoom\n }\n return subRoom\n }\n\n /**\n * @method getUsersProperty\n * @private\n * @param {Object} subRoom - The sub-room instance.\n * @returns {Object|null} The users property of the sub-room, or null if not found.\n * \n * @example\n * ```typescript\n * // This method is private and called internally\n * function internalGetUsers(subRoom) {\n * const users = this.getUsersProperty(subRoom);\n * console.log(\"Users:\", users);\n * }\n * ```\n */\n\n private getUsersProperty(subRoom) {\n const meta = subRoom.constructor[\"_propertyMetadata\"];\n const propId = meta?.get(\"users\");\n if (propId) {\n return subRoom[propId];\n }\n return null;\n }\n\n /**\n * @method onConnect\n * @async\n * @param {Party.Connection} conn - The connection object for the new user.\n * @param {Party.ConnectionContext} ctx - The context of the connection.\n * @description Handles a new user connection, creates a user object, and sends initial sync data.\n * @returns {Promise<void>}\n * \n * @example\n * ```typescript\n * server.onConnect = async (conn, ctx) => {\n * await server.onConnect(conn, ctx);\n * console.log(\"New user connected:\", conn.id);\n * };\n * ```\n */\n async onConnect(conn: Party.Connection, ctx: Party.ConnectionContext) {\n const subRoom = await this.getSubRoom({\n getMemoryAll: true,\n })\n // Generate a unique public ID for the user\n const publicId = generateShortUUID()\n let user = null;\n const signal = this.getUsersProperty(subRoom);\n if (signal) {\n const { classType } = signal.options;\n // Create a new user instance based on the defined class type\n user = isClass(classType) ? new classType() : classType(conn, ctx);\n signal()[publicId] = user;\n }\n // Call the room's onJoin method if it exists\n await awaitReturn(subRoom[\"onJoin\"]?.(user, conn, ctx));\n conn.setState({ publicId });\n // Send initial sync data to the new connection\n conn.send(\n JSON.stringify({\n type: \"sync\",\n value: {\n pId: publicId,\n ...subRoom.$memoryAll,\n },\n })\n );\n }\n\n /**\n * @method onMessage\n * @async\n * @param {string} message - The message received from a user.\n * @param {Party.Connection} sender - The connection object of the sender.\n * @description Processes incoming messages and triggers corresponding actions in the sub-room.\n * @returns {Promise<void>}\n * \n * @example\n * ```typescript\n * server.onMessage = async (message, sender) => {\n * await server.onMessage(message, sender);\n * console.log(\"Message processed from:\", sender.id);\n * };\n * ```\n */\n\n async onMessage(message: string, sender: Party.Connection) {\n let json\n try {\n json = JSON.parse(message)\n }\n catch (e) {\n return;\n }\n // Validate incoming messages\n const result = Message.safeParse(json);\n if (!result.success) {\n return;\n }\n const subRoom = await this.getSubRoom()\n const actions = subRoom.constructor[\"_actionMetadata\"];\n if (actions) {\n const signal = this.getUsersProperty(subRoom);\n const { publicId } = sender.state as any;\n const user = signal?.()[publicId];\n const actionName = actions.get(result.data.action);\n if (actionName) {\n // Validate action body if a validation schema is defined\n if (actionName.bodyValidation) {\n const bodyResult = actionName.bodyValidation.safeParse(\n result.data.value\n );\n if (!bodyResult.success) {\n return;\n }\n }\n // Execute the action\n await awaitReturn(\n subRoom[actionName.key](user, result.data.value, sender)\n );\n }\n }\n }\n\n /**\n * @method onClose\n * @async\n * @param {Party.Connection} conn - The connection object of the disconnecting user.\n * @description Handles user disconnection, removing them from the room and triggering the onLeave event.\n * @returns {Promise<void>}\n * \n * @example\n * ```typescript\n * server.onClose = async (conn) => {\n * await server.onClose(conn);\n * console.log(\"User disconnected:\", conn.id);\n * };\n * ```\n */\n async onClose(conn: Party.Connection) {\n const subRoom = await this.getSubRoom()\n const signal = this.getUsersProperty(subRoom);\n const { publicId } = conn.state as any;\n const user = signal?.()[publicId];\n // Call the room's onLeave method if it exists\n await awaitReturn(subRoom[\"onLeave\"]?.(user, conn));\n if (signal) {\n // Remove the user from the room\n delete signal()[publicId];\n }\n }\n}\n","import {\n ArraySubject,\n ObjectSubject,\n isSignal,\n type WritableSignal,\n} from \"@signe/reactive\";\nimport { isInstanceOfClass, isObject } from \"./utils\";\n\ninterface SyncOptions {\n onSync?: (value: Map<string, any>) => void;\n onPersist?: (value: Set<string>) => void;\n}\n\ninterface TypeOptions {\n syncToClient?: boolean;\n persist?: boolean;\n classType?: any;\n}\n\n/**\n * Synchronizes an instance by adding `$valuesChanges` methods for state management.\n *\n * This function initializes a cache for syncing and persisting values. It adds methods to the instance\n * to set values, mark values for persistence, and check and retrieve values from the cache.\n * Optionally, callbacks can be provided to handle synchronization and persistence events.\n *\n * @param {Record<string, any>} instance - The instance to be synchronized.\n * @param {SyncOptions} [options={}] - Optional synchronization options.\n * @param {Function} [options.onSync] - Callback function to be called on value sync with the current cache.\n * @param {Function} [options.onPersist] - Callback function to be called on value persistence with the current cache.\n *\n * @example\n * class TestClass {\n * @sync() count = signal(0);\n * @sync() text = signal('hello');\n * }\n * const instance = new TestClass();\n * syncClass(instance, {\n * onSync: (cache) => console.log('Sync cache:', cache),\n * onPersist: (cache) => console.log('Persist cache:', cache),\n * });\n */\nexport const syncClass = (instance: any, options: SyncOptions = {}) => {\n const cacheSync = new Map();\n const cachePersist = new Set<string>();\n instance.$valuesChanges = {\n set: (path: string, value: any) => {\n cacheSync.set(path, value);\n options.onSync?.(cacheSync);\n },\n setPersist: (path: string) => {\n if (path == \"\") path = \".\";\n cachePersist.add(path);\n options.onPersist?.(cachePersist);\n },\n has: (path: string) => {\n return cacheSync.has(path);\n },\n get: (path: string) => {\n return cacheSync.get(path);\n },\n };\n createSyncClass(instance);\n};\n\n/**\n * Creates a snapshot of the current state of an instance's signals.\n *\n * This function iterates over the signals stored in the instance's $snapshot property.\n * If a signal's value is not an object or array and the signal's persist option is true or undefined,\n * it adds the signal's value to the returned snapshot object.\n *\n * @param {Record<string, any>} instance - The instance containing the $snapshot map of signals.\n * @returns {Record<string, any>} - An object representing the persisted snapshot of the instance's state.\n *\n * @example\n * ```typescript\n * class TestClass {\n * @sync() count = signal(0);\n * @sync() text = signal('hello');\n * }\n * const instance = new TestClass();\n * syncClass(instance);\n * const snapshot = createStatesSnapshot(instance);\n * console.log(snapshot); // { count: 0, text: 'hello' }\n * ```\n */\nexport function createStatesSnapshot(instance: Record<string, any>): Record<string, any> {\n let persistObject: any = {};\n if (instance.$snapshot) {\n for (const key of instance.$snapshot.keys()) {\n const signal = instance.$snapshot.get(key);\n const persist = signal.options.persist ?? true;\n let value = signal();\n if (isObject(value) || Array.isArray(value)) {\n break;\n }\n if (persist) {\n persistObject[key] = value;\n }\n }\n }\n return persistObject;\n}\n\nexport function setMetadata(target: any, key: string, value: any) {\n const meta = target.constructor._propertyMetadata;\n const propId = meta?.get(key);\n if (propId) {\n if (isSignal(target[propId])) {\n target[propId].set(value);\n } else {\n target[propId] = value;\n }\n }\n}\n\nexport const createSyncClass = (\n currentClass: any,\n parentKey: any = null,\n parentClass = null,\n path = \"\"\n) => {\n currentClass.$path = path;\n if (parentClass) {\n currentClass.$valuesChanges = parentClass.$valuesChanges;\n }\n if (parentKey) {\n setMetadata(currentClass, \"id\", parentKey);\n }\n if (currentClass.$snapshot) {\n for (const key of currentClass.$snapshot.keys()) {\n const signal = currentClass.$snapshot.get(key);\n const syncToClient = signal.options.syncToClient ?? true;\n const persist = signal.options.persist ?? true;\n let value = signal();\n if (isObject(value) || Array.isArray(value)) {\n value = { ...value };\n }\n const newPath = (path ? path + \".\" : \"\") + key;\n if (syncToClient) {\n currentClass.$valuesChanges.set(newPath, value);\n }\n if (persist) {\n if (parentClass) currentClass.$valuesChanges.setPersist(path);\n }\n }\n }\n};\n\nexport const type = (\n _signal: any,\n path: string,\n options: TypeOptions = {},\n currentInstance: any\n): WritableSignal<any> => {\n const syncToClient = options.syncToClient ?? true;\n const persist = options.persist ?? true;\n let init = true;\n _signal.options = options;\n _signal.observable.subscribe((value) => {\n const check = currentInstance.$valuesChanges;\n\n function savePath(propPath, value) {\n if (syncToClient) check.set(propPath, value);\n if (persist) {\n check.setPersist(currentInstance.$path);\n }\n }\n\n if (init) {\n init = false;\n return;\n }\n if (currentInstance.$path !== undefined) {\n const propPath =\n (currentInstance.$path ? currentInstance.$path + \".\" : \"\") + path;\n if (_signal._subject instanceof ObjectSubject) {\n const newPath =\n (currentInstance.$path ? currentInstance.$path + \".\" : \"\") +\n path +\n \".\" +\n value.key;\n\n if (value.type == \"add\") {\n if (isInstanceOfClass(value.value)) {\n createSyncClass(value.value, value.key, currentInstance, newPath);\n } else {\n savePath(newPath, value.value);\n }\n } else if (value.type == \"update\") {\n if (isObject(value.value) || Array.isArray(value.value)) {\n createSyncClass(value.value, value.key, currentInstance, newPath);\n } else {\n savePath(newPath, value.value);\n }\n } else if (value.type == \"remove\") {\n savePath(newPath, \"$delete\");\n }\n } else if (_signal._subject instanceof ArraySubject) {\n const newPath = propPath + \".\" + value.index;\n const firstItem = value.items[0];\n if (value.type == \"add\") {\n if (isInstanceOfClass(firstItem)) {\n createSyncClass(firstItem, value.key, currentInstance, newPath);\n } else {\n savePath(newPath, firstItem);\n }\n } else if (value.type == \"update\") {\n if (isObject(firstItem) || Array.isArray(firstItem)) {\n createSyncClass(firstItem, value.key, currentInstance, newPath);\n } else {\n savePath(newPath, firstItem);\n }\n } else if (value.type == \"remove\") {\n savePath(newPath, \"$delete\");\n }\n } else {\n savePath(propPath, value);\n }\n }\n });\n\n if (!currentInstance.$snapshot) {\n currentInstance.$snapshot = new Map();\n }\n\n currentInstance.$snapshot.set(path, _signal);\n\n return _signal;\n};\n","import { isSignal } from \"@signe/reactive\";\nimport { setMetadata } from \"./core\";\nimport { isClass } from \"./utils\";\n\n/**\n * Loads values into the root instance by paths or from an object.\n * \n * @param {object} rootInstance - The instance into which values will be loaded.\n * @param {object} values - The values to load, either as paths or an object.\n * @param {boolean} [valueIsObject=false] - If true, `values` is treated as an object.\n * @example\n * // Using paths:\n * load(instance, { 'position.x': 10, 'position.y': 20 });\n * \n * // Using an object:\n * load(instance, { position: { x: 10, y: 20 } }, true);\n */\nexport function load(rootInstance: any, values: { [path: string]: any }): void;\nexport function load(\n rootInstance: any,\n values: object,\n valueIsObject: true\n): void;\nexport function load(\n rootInstance: any,\n values: { [path: string]: any } | object,\n valueIsObject?: boolean\n) {\n if (valueIsObject) {\n loadFromObject(rootInstance, values);\n } else {\n loadFromPaths(rootInstance, values);\n }\n}\n\n/**\n * Loads values into the root instance using paths.\n * \n * @param {object} rootInstance - The instance into which values will be loaded.\n * @param {object} values - The values to load, with keys as paths.\n * @example\n * loadFromPaths(instance, { 'position.x': 10, 'position.y': 20 });\n */\nfunction loadFromPaths(rootInstance: any, values: { [path: string]: any }) {\n for (const [path, value] of Object.entries(values)) {\n const parts = path.split(\".\");\n loadValue(rootInstance, parts, value);\n }\n}\n\n/**\n * Recursively loads values from an object into the root instance.\n * \n * @param {object} rootInstance - The instance into which values will be loaded.\n * @param {object} values - The values to load.\n * @param {string} [currentPath=\"\"] - The current path in the recursion.\n * @example\n * loadFromObject(instance, { position: { x: 10, y: 20 } });\n */\nfunction loadFromObject(\n rootInstance: any,\n values: object,\n currentPath: string = \"\"\n) {\n for (const [key, value] of Object.entries(values)) {\n const newPath = currentPath ? `${currentPath}.${key}` : key;\n if (typeof value === \"object\" && !Array.isArray(value)) {\n loadFromObject(rootInstance, value, newPath);\n } else {\n const parts = newPath.split(\".\");\n loadValue(rootInstance, parts, value);\n }\n }\n}\n\n/**\n * Sets a value in the root instance by navigating through the path parts.\n * \n * @param {object} rootInstance - The instance into which the value will be set.\n * @param {string[]} parts - The parts of the path.\n * @param {any} value - The value to set.\n * @example\n * loadValue(instance, ['position', 'x'], 10);\n */\nfunction loadValue(rootInstance: any, parts: string[], value: any) {\n let current: any = rootInstance;\n\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i];\n\n if (i === parts.length - 1) {\n if (value == '$delete') {\n if (isSignal(current)) {\n current = current();\n }\n Reflect.deleteProperty(current, part);\n }\n else if (current[part]?._subject) {\n current[part].set(value);\n }\n } else {\n if (isSignal(current)) {\n current = current();\n }\n const currentValue = current[part];\n if (currentValue === undefined) {\n const parentInstance = getByPath(\n rootInstance,\n parts.slice(0, i).join(\".\")\n );\n const classType = parentInstance?.options?.classType;\n if (classType) {\n current[part] = !isClass(classType) ? classType(part) : new classType();\n setMetadata(current[part], 'id', part)\n } else {\n current[part] = {};\n }\n }\n current = current[part];\n }\n }\n}\n\n/**\n * Retrieves a value from the root instance by a path.\n * \n * @param {object} root - The root instance.\n * @param {string} path - The path to the value.\n * @returns {any} - The value at the specified path.\n * @example\n * const value = getByPath(instance, 'position.x');\n */\nexport function getByPath(root: any, path: string) {\n const parts = path.split(\".\");\n let current = root;\n for (const part of parts) {\n if (isSignal(current)) {\n current = current();\n }\n if (current[part]) {\n current = current[part];\n } else {\n return undefined;\n }\n }\n return current;\n}\n","import { dset } from \"dset\";\n\n/**\n * Checks if a value is a Promise.\n *\n * @param {unknown} value - The value to check.\n * @returns {boolean} - Returns true if the value is a Promise, otherwise false.\n *\n * @example\n * isPromise(Promise.resolve()); // true\n * isPromise(42); // false\n */\nexport function isPromise(value: unknown): value is Promise<any> {\n return value instanceof Promise;\n}\n\n/**\n * Awaits the given value if it is a Promise, otherwise returns the value directly.\n *\n * @param {unknown} val - The value to await or return.\n * @returns {Promise<any>} - Returns a Promise that resolves to the value.\n *\n * @example\n * awaitReturn(Promise.resolve(42)); // 42\n * awaitReturn(42); // 42\n */\nexport async function awaitReturn(val: unknown): Promise<any> {\n return isPromise(val) ? await val : val;\n}\n\n/**\n * Checks if a value is a class.\n *\n * @param {unknown} obj - The value to check.\n * @returns {boolean} - Returns true if the value is a class, otherwise false.\n *\n * @example\n * class MyClass {}\n * isClass(MyClass); // true\n * isClass(() => {}); // false\n */\nexport function isClass(obj: unknown): boolean {\n return (\n typeof obj === \"function\" &&\n obj.prototype &&\n obj.prototype.constructor === obj\n );\n}\n\n\n/**\n * Creates a throttled function that only invokes the provided function at most once per every wait milliseconds.\n *\n * The throttled function comes with a cancel method to cancel delayed invocations.\n * If the throttled function is invoked more than once during the wait timeout,\n * it will call the provided function with the latest arguments.\n *\n * @template F - The type of the function to throttle.\n * @param {F} func - The function to throttle.\n * @param {number} wait - The number of milliseconds to throttle invocations to.\n * @returns {(...args: Parameters<F>) => void} - Returns the new throttled function.\n *\n * @example\n * const log = throttle((message) => console.log(message), 1000);\n * log(\"Hello\"); // Will log \"Hello\" immediately\n * log(\"World\"); // Will log \"World\" after 1 second, if no other calls to log() are made within the 1 second.\n */\nexport function throttle<F extends (...args: any[]) => any>(\n func: F,\n wait: number\n): (...args: Parameters<F>) => void {\n let timeout: ReturnType<typeof setTimeout> | null = null;\n let lastArgs: Parameters<F> | null = null;\n\n return function (...args: Parameters<F>) {\n if (!timeout) {\n func(...args);\n timeout = setTimeout(() => {\n if (lastArgs) {\n func(...lastArgs);\n lastArgs = null;\n }\n timeout = null;\n }, wait);\n } else {\n lastArgs = args;\n }\n };\n}\n\n/**\n * Extracts parameters from a given string based on a specified pattern.\n *\n * The pattern can include placeholders in the form of {paramName}, which will be\n * extracted from the input string if they match.\n *\n * @param {string} pattern - The pattern containing placeholders.\n * @param {string} str - The string to extract parameters from.\n * @returns {{ [key: string]: string } | null} - An object containing the extracted parameters,\n * or null if the string does not match the pattern.\n *\n * @example\n * // returns { id: '123' }\n * extractParams('game-{id}', 'game-123');\n *\n * @example\n * // returns { foo: 'abc', bar: 'xyz' }\n * extractParams('test-{foo}-{bar}', 'test-abc-xyz');\n *\n */\nexport function extractParams(\n pattern: string,\n str: string\n): { [key: string]: string } | null {\n // Replace placeholders in the pattern with named capture groups\n const regexPattern = pattern.replace(/{(\\w+)}/g, \"(?<$1>[\\\\w-]+)\");\n\n // Create a strict regular expression from the pattern\n const regex = new RegExp(`^${regexPattern}$`);\n const match = regex.exec(str);\n\n // If a match is found and groups are present, return the captured groups\n if (match && match.groups) {\n return match.groups;\n } else if (pattern === str) {\n // If the pattern exactly matches the string, return an empty object\n return {};\n } else {\n // Otherwise, return null\n return null;\n }\n}\n\n/**\n * Removes a property from an object based on a dot-separated key string or an array of keys.\n *\n * The function modifies the original object by deleting the specified property.\n * It safely handles dangerous keys like __proto__, constructor, and prototype.\n *\n * @param {Record<string, any>} obj - The object from which to remove the property.\n * @param {string | string[]} keys - The key(s) specifying the property to remove. Can be a dot-separated string or an array of strings.\n *\n * @example\n * const obj = { a: { b: { c: 3 } } };\n * dremove(obj, 'a.b.c');\n * // obj is now { a: { b: {} } }\n *\n * @example\n * const obj = { a: 1, b: 2 };\n * dremove(obj, 'a');\n * // obj is now { b: 2 }\n *\n * @example\n * const obj = { a: { b: { c: 3 } } };\n * dremove(obj, ['a', 'b', 'c']);\n * // obj is now { a: { b: {} } }\n */\nexport function dremove(\n obj: Record<string, any>,\n keys: string | string[]\n): void {\n // If keys is a string, convert it to an array using the \".\" separator\n if (typeof keys === \"string\") {\n keys = keys.split(\".\");\n }\n\n let i = 0;\n const l = keys.length;\n let t = obj;\n let k;\n\n while (i < l - 1) {\n k = keys[i++];\n if (k === \"__proto__\" || k === \"constructor\" || k === \"prototype\") return; // Avoid dangerous keys\n if (typeof t[k] !== \"object\" || t[k] === null) return; // If the object doesn't exist, stop\n t = t[k];\n }\n\n k = keys[i];\n if (\n t &&\n typeof t === \"object\" &&\n !(k === \"__proto__\" || k === \"constructor\" || k === \"prototype\")\n ) {\n delete t[k];\n }\n}\n\n/**\n * Builds an object from a map of values and updates the provided memory object.\n *\n * For each key-value pair in the map, this function sets the value at the given path in the `memoryObj`.\n * If the value is \"$delete\", it removes the corresponding path from `allMemory`.\n *\n * @param {Map<string, any>} valuesMap - A map where the keys are paths and the values are the values to set at those paths.\n * @param {Record<string, any>} allMemory - The object to update based on the values in the map.\n * @returns {Record<string, any>} - The built memory object with the applied values from the map.\n *\n * @example\n * const valuesMap = new Map();\n * valuesMap.set('a.b.c', 1);\n * valuesMap.set('x.y.z', '$delete');\n * const allMemory = { x: { y: { z: 2 } } };\n * const result = buildObject(valuesMap, allMemory);\n * // result is { a: { b: { c: 1 } }, x: { y: { z: '$delete' } } }\n * // allMemory is { a: { b: { c: 1 } }, x: { y: {} } }\n */\nexport function buildObject(valuesMap: Map<string, any>, allMemory: Record<string, any>): Record<string, any> {\n let memoryObj = {};\n for (let path of valuesMap.keys()) {\n const value = valuesMap.get(path);\n dset(memoryObj, path, value);\n if (value === \"$delete\") {\n dremove(allMemory, path);\n } else {\n dset(allMemory, path, value);\n }\n }\n return memoryObj;\n}"],"mappings":";;;;AAAO,SAASA,OAAOC,MAAcC,gBAAe;AAClD,SAAO,SAAUC,QAAaC,aAAmB;AAC/C,QAAI,CAACD,OAAOE,YAAYC,iBAAiB;AACvCH,aAAOE,YAAYC,kBAAkB,oBAAIC,IAAAA;IAC3C;AACAJ,WAAOE,YAAYC,gBAAgBE,IAAIP,MAAM;MAC3CQ,KAAKL;MACLF;IACF,CAAA;EACF;AACF;AAVgBF;AAoBT,SAASU,KAAKC,SAAoB;AACvC,SAAO,SAAUR,QAAW;AAC1BA,WAAOS,OAAOD,QAAQC;AACtBT,WAAOU,WAAWF,QAAQE;AAC1BV,WAAOW,kBAAkBH,QAAQG;AACjCX,WAAOY,eAAeJ,QAAQI;EAChC;AACF;AAPgBL;;;ACIT,SAASM,QAAQC,KAAQ;AAC9B,SACE,OAAOA,QAAQ,cACfA,IAAIC,aACJD,IAAIC,UAAUC,gBAAgBF;AAElC;AANgBD;AAkBT,IAAMI,WAAW,wBAACC,SACvBA,QAAQ,OAAOA,SAAS,YAAY,CAACC,MAAMC,QAAQF,IAAAA,KAASA,SAAS,MAD/C;AA0BjB,SAASG,oBAAAA;AACd,QAAMC,QAAQ;AACd,MAAIC,OAAO;AACX,WAASC,IAAI,GAAGA,IAAI,GAAGA,KAAK;AACxB,UAAMC,cAAcC,KAAKC,MAAMD,KAAKE,OAAM,IAAKN,MAAMO,MAAM;AAC3DN,YAAQD,MAAMG,WAAAA;EAClB;AACA,SAAOF;AACT;AARgBF;;;AClEhB,IAAMS,kBAAN,MAAMA,iBAAAA;EAFN,OAEMA;;;EACMC,SAAgC,oBAAIC,IAAAA;EAC5CC,KAAKC,kBAAAA;EAELC,iBAAiBC,OAAOC,IAAI;AACxB,SAAKN,OAAOO,IAAIF,OAAOC,EAAAA;EAC3B;EAEAE,oBAAoBH,OAAOC,IAAI;AAC3B,SAAKN,OAAOS,OAAOJ,KAAAA;EACvB;EAEAK,SAASL,OAAOM,MAAM;AAClB,SAAKX,OAAOY,IAAIP,KAAAA,IAASM,IAAAA;EAC7B;AACJ;AAEA,IAAME,cAAN,MAAMA,aAAAA;EAnBN,OAmBMA;;;EACMC,UAA4B,oBAAIb,IAAAA;EAExC,MAAMW,IAAIG,KAAa;AACnB,WAAO,KAAKD,QAAQF,IAAIG,GAAAA;EAC5B;EAEA,MAAMC,IAAID,KAAaE,OAAY;AAC/B,SAAKH,QAAQP,IAAIQ,KAAKE,KAAAA;EAC1B;EAEA,MAAMC,OAAO;AACT,WAAO,KAAKJ;EAChB;AACJ;AAEA,IAAMK,gBAAN,MAAMA,eAAAA;EAnCN,OAmCMA;;;;EACIC;EACRN;EAEAO,YAAmBnB,IAAa;SAAbA,KAAAA;SAHXkB,UAAwC,oBAAInB,IAAAA;SACpDa,UAAU,IAAID,YAAAA;AAGZ,SAAKX,KAAKA,MAAMC,kBAAAA;EAClB;EAEAmB,WAAWC,QAAQ;AACjB,UAAMC,SAAS,IAAIzB,gBAAAA;AACnB,SAAKqB,QAAQb,IAAIiB,OAAOtB,IAAIqB,MAAAA;AAC5BA,WAAOrB,KAAKsB,OAAOtB;EACrB;EAEAuB,UAAUd,MAAW;AACnB,SAAKS,QAAQM,QAAQ,CAACH,WAAAA;AACpBA,aAAOb,SAAS,WAAWC,IAAAA;IAC7B,CAAA;EACF;EAEAgB,QAAQ;AACN,SAAKP,QAAQO,MAAK;EACpB;AACF;AAEO,IAAMC,iBAAN,MAAMA;EA5Db,OA4DaA;;;EACXC,QAAa,CAAC;EAEdC,SAASb,OAAY;AACnB,SAAKY,QAAQZ;EACf;AACF;AAEO,IAAMc,WAAWZ;AACjB,IAAMa,WAAWjC;;;ACrExB,SAASkC,QAAAA,aAAY;AACrB,OAAOC,OAAO;;;ACDd,SACEC,cACAC,eACAC,gBAEK;AAqCA,IAAMC,YAAY,wBAACC,UAAeC,UAAuB,CAAC,MAAC;AAChE,QAAMC,YAAY,oBAAIC,IAAAA;AACtB,QAAMC,eAAe,oBAAIC,IAAAA;AACzBL,WAASM,iBAAiB;IACxBC,KAAK,wBAACC,MAAcC,UAAAA;AAClBP,gBAAUK,IAAIC,MAAMC,KAAAA;AACpBR,cAAQS,SAASR,SAAAA;IACnB,GAHK;IAILS,YAAY,wBAACH,SAAAA;AACX,UAAIA,QAAQ,GAAIA,QAAO;AACvBJ,mBAAaQ,IAAIJ,IAAAA;AACjBP,cAAQY,YAAYT,YAAAA;IACtB,GAJY;IAKZU,KAAK,wBAACN,SAAAA;AACJ,aAAON,UAAUY,IAAIN,IAAAA;IACvB,GAFK;IAGLO,KAAK,wBAACP,SAAAA;AACJ,aAAON,UAAUa,IAAIP,IAAAA;IACvB,GAFK;EAGP;AACAQ,kBAAgBhB,QAAAA;AAClB,GArByB;AA6ClB,SAASiB,qBAAqBjB,UAA6B;AAChE,MAAIkB,gBAAqB,CAAC;AAC1B,MAAIlB,SAASmB,WAAW;AACtB,eAAWC,OAAOpB,SAASmB,UAAUE,KAAI,GAAI;AAC3C,YAAMC,SAAStB,SAASmB,UAAUJ,IAAIK,GAAAA;AACtC,YAAMG,UAAUD,OAAOrB,QAAQsB,WAAW;AAC1C,UAAId,QAAQa,OAAAA;AACZ,UAAIE,SAASf,KAAAA,KAAUgB,MAAMC,QAAQjB,KAAAA,GAAQ;AAC3C;MACF;AACA,UAAIc,SAAS;AACXL,sBAAcE,GAAAA,IAAOX;MACvB;IACF;EACF;AACA,SAAOS;AACT;AAhBgBD;AAkBT,SAASU,YAAYC,QAAaR,KAAaX,OAAU;AAC9D,QAAMoB,OAAOD,OAAOE,YAAYC;AAChC,QAAMC,SAASH,MAAMd,IAAIK,GAAAA;AACzB,MAAIY,QAAQ;AACV,QAAIC,SAASL,OAAOI,MAAAA,CAAO,GAAG;AAC5BJ,aAAOI,MAAAA,EAAQzB,IAAIE,KAAAA;IACrB,OAAO;AACLmB,aAAOI,MAAAA,IAAUvB;IACnB;EACF;AACF;AAVgBkB;AAYT,IAAMX,kBAAkB,wBAC7BkB,cACAC,YAAiB,MACjBC,cAAc,MACd5B,OAAO,OAAE;AAET0B,eAAaG,QAAQ7B;AACrB,MAAI4B,aAAa;AACfF,iBAAa5B,iBAAiB8B,YAAY9B;EAC5C;AACA,MAAI6B,WAAW;AACbR,gBAAYO,cAAc,MAAMC,SAAAA;EAClC;AACA,MAAID,aAAaf,WAAW;AAC1B,eAAWC,OAAOc,aAAaf,UAAUE,KAAI,GAAI;AAC/C,YAAMC,SAASY,aAAaf,UAAUJ,IAAIK,GAAAA;AAC1C,YAAMkB,eAAehB,OAAOrB,QAAQqC,gBAAgB;AACpD,YAAMf,UAAUD,OAAOrB,QAAQsB,WAAW;AAC1C,UAAId,QAAQa,OAAAA;AACZ,UAAIE,SAASf,KAAAA,KAAUgB,MAAMC,QAAQjB,KAAAA,GAAQ;AAC3CA,gBAAQ;UAAE,GAAGA;QAAM;MACrB;AACA,YAAM8B,WAAW/B,OAAOA,OAAO,MAAM,MAAMY;AAC3C,UAAIkB,cAAc;AAChBJ,qBAAa5B,eAAeC,IAAIgC,SAAS9B,KAAAA;MAC3C;AACA,UAAIc,SAAS;AACX,YAAIa,YAAaF,cAAa5B,eAAeK,WAAWH,IAAAA;MAC1D;IACF;EACF;AACF,GA/B+B;;;ACrH/B,SAASgC,YAAAA,iBAAgB;AAuBlB,SAASC,KACdC,cACAC,QACAC,eAAuB;AAEvB,MAAIA,eAAe;AACjBC,mBAAeH,cAAcC,MAAAA;EAC/B,OAAO;AACLG,kBAAcJ,cAAcC,MAAAA;EAC9B;AACF;AAVgBF;AAoBhB,SAASK,cAAcJ,cAAmBC,QAA+B;AACvE,aAAW,CAACI,MAAMC,KAAAA,KAAUC,OAAOC,QAAQP,MAAAA,GAAS;AAClD,UAAMQ,QAAQJ,KAAKK,MAAM,GAAA;AACzBC,cAAUX,cAAcS,OAAOH,KAAAA;EACjC;AACF;AALSF;AAgBT,SAASD,eACPH,cACAC,QACAW,cAAsB,IAAE;AAExB,aAAW,CAACC,KAAKP,KAAAA,KAAUC,OAAOC,QAAQP,MAAAA,GAAS;AACjD,UAAMa,UAAUF,cAAc,GAAGA,WAAAA,IAAeC,GAAAA,KAAQA;AACxD,QAAI,OAAOP,UAAU,YAAY,CAACS,MAAMC,QAAQV,KAAAA,GAAQ;AACtDH,qBAAeH,cAAcM,OAAOQ,OAAAA;IACtC,OAAO;AACL,YAAML,QAAQK,QAAQJ,MAAM,GAAA;AAC5BC,gBAAUX,cAAcS,OAAOH,KAAAA;IACjC;EACF;AACF;AAdSH;AAyBT,SAASQ,UAAUX,cAAmBS,OAAiBH,OAAU;AAC/D,MAAIW,UAAejB;AAEnB,WAASkB,IAAI,GAAGA,IAAIT,MAAMU,QAAQD,KAAK;AACrC,UAAME,OAAOX,MAAMS,CAAAA;AAEnB,QAAIA,MAAMT,MAAMU,SAAS,GAAG;AAC1B,UAAIb,SAAS,WAAW;AACtB,YAAIe,UAASJ,OAAAA,GAAU;AACrBA,oBAAUA,QAAAA;QACZ;AACAK,gBAAQC,eAAeN,SAASG,IAAAA;MAClC,WACSH,QAAQG,IAAAA,GAAOI,UAAU;AAChCP,gBAAQG,IAAAA,EAAMK,IAAInB,KAAAA;MACpB;IACF,OAAO;AACL,UAAIe,UAASJ,OAAAA,GAAU;AACrBA,kBAAUA,QAAAA;MACZ;AACA,YAAMS,eAAeT,QAAQG,IAAAA;AAC7B,UAAIM,iBAAiBC,QAAW;AAC9B,cAAMC,iBAAiBC,UACrB7B,cACAS,MAAMqB,MAAM,GAAGZ,CAAAA,EAAGa,KAAK,GAAA,CAAA;AAEzB,cAAMC,YAAYJ,gBAAgBK,SAASD;AAC3C,YAAIA,WAAW;AACbf,kBAAQG,IAAAA,IAAQ,CAACc,QAAQF,SAAAA,IAAaA,UAAUZ,IAAAA,IAAQ,IAAIY,UAAAA;AAC5DG,sBAAYlB,QAAQG,IAAAA,GAAO,MAAMA,IAAAA;QACnC,OAAO;AACLH,kBAAQG,IAAAA,IAAQ,CAAC;QACnB;MACF;AACAH,gBAAUA,QAAQG,IAAAA;IACpB;EACF;AACF;AArCST;AAgDF,SAASkB,UAAUO,MAAW/B,MAAY;AAC/C,QAAMI,QAAQJ,KAAKK,MAAM,GAAA;AACzB,MAAIO,UAAUmB;AACd,aAAWhB,QAAQX,OAAO;AACxB,QAAIY,UAASJ,OAAAA,GAAU;AACrBA,gBAAUA,QAAAA;IACZ;AACA,QAAIA,QAAQG,IAAAA,GAAO;AACjBH,gBAAUA,QAAQG,IAAAA;IACpB,OAAO;AACL,aAAOO;IACT;EACF;AACA,SAAOV;AACT;AAdgBY;;;ACpIhB,SAASQ,YAAY;AAYd,SAASC,UAAUC,OAAc;AACtC,SAAOA,iBAAiBC;AAC1B;AAFgBF;AAchB,eAAsBG,YAAYC,KAAY;AAC5C,SAAOJ,UAAUI,GAAAA,IAAO,MAAMA,MAAMA;AACtC;AAFsBD;AAef,SAASE,SAAQC,KAAY;AAClC,SACE,OAAOA,QAAQ,cACfA,IAAIC,aACJD,IAAIC,UAAUC,gBAAgBF;AAElC;AANgBD,OAAAA,UAAAA;AA0BT,SAASI,SACdC,MACAC,MAAY;AAEZ,MAAIC,UAAgD;AACpD,MAAIC,WAAiC;AAErC,SAAO,YAAaC,MAAmB;AACrC,QAAI,CAACF,SAAS;AACZF,WAAAA,GAAQI,IAAAA;AACRF,gBAAUG,WAAW,MAAA;AACnB,YAAIF,UAAU;AACZH,eAAAA,GAAQG,QAAAA;AACRA,qBAAW;QACb;AACAD,kBAAU;MACZ,GAAGD,IAAAA;IACL,OAAO;AACLE,iBAAWC;IACb;EACF;AACF;AArBgBL;AA2CT,SAASO,cACdC,SACAC,KAAW;AAGX,QAAMC,eAAeF,QAAQG,QAAQ,YAAY,gBAAA;AAGjD,QAAMC,QAAQ,IAAIC,OAAO,IAAIH,YAAAA,GAAe;AAC5C,QAAMI,QAAQF,MAAMG,KAAKN,GAAAA;AAGzB,MAAIK,SAASA,MAAME,QAAQ;AACzB,WAAOF,MAAME;EACf,WAAWR,YAAYC,KAAK;AAE1B,WAAO,CAAC;EACV,OAAO;AAEL,WAAO;EACT;AACF;AArBgBF;AA+CT,SAASU,QACdpB,KACAqB,MAAuB;AAGvB,MAAI,OAAOA,SAAS,UAAU;AAC5BA,WAAOA,KAAKC,MAAM,GAAA;EACpB;AAEA,MAAIC,IAAI;AACR,QAAMC,IAAIH,KAAKI;AACf,MAAIC,IAAI1B;AACR,MAAI2B;AAEJ,SAAOJ,IAAIC,IAAI,GAAG;AAChBG,QAAIN,KAAKE,GAAAA;AACT,QAAII,MAAM,eAAeA,MAAM,iBAAiBA,MAAM,YAAa;AACnE,QAAI,OAAOD,EAAEC,CAAAA,MAAO,YAAYD,EAAEC,CAAAA,MAAO,KAAM;AAC/CD,QAAIA,EAAEC,CAAAA;EACR;AAEAA,MAAIN,KAAKE,CAAAA;AACT,MACEG,KACA,OAAOA,MAAM,YACb,EAAEC,MAAM,eAAeA,MAAM,iBAAiBA,MAAM,cACpD;AACA,WAAOD,EAAEC,CAAAA;EACX;AACF;AA7BgBP;AAkDT,SAASQ,YAAYC,WAA6BC,WAA8B;AACrF,MAAIC,YAAY,CAAC;AACjB,WAASC,QAAQH,UAAUR,KAAI,GAAI;AACjC,UAAM1B,QAAQkC,UAAUI,IAAID,IAAAA;AAC5BE,SAAKH,WAAWC,MAAMrC,KAAAA;AACtB,QAAIA,UAAU,WAAW;AACvByB,cAAQU,WAAWE,IAAAA;IACrB,OAAO;AACLE,WAAKJ,WAAWE,MAAMrC,KAAAA;IACxB;EACF;AACA,SAAOoC;AACT;AAZgBH;;;AH7LhB,IAAMO,UAAUC,EAAEC,OAAO;EACvBC,QAAQF,EAAEG,OAAM;EAChBC,OAAOJ,EAAEK,IAAG;AACd,CAAA;AA4BO,IAAMC,SAAN,MAAMA;EAjDb,OAiDaA;;;;EACXC;EACAC;;;;;;;;;;EAWAC,YAAqBC,MAAkB;SAAlBA,OAAAA;SAZrBH,UAAU;SACVC,QAAe,CAAA;EAWyB;;;;;;;;;;;;EAaxC,IAAIG,cAAuB;AACzB,WAAO,CAAC,CAAC,KAAK,SAAA,GAAYC;EAC5B;;;;;;;;;;;;;;;EAiBA,MAAMC,UAAU;AAGd,QAAI,CAAC,KAAKF,aAAa;AACrB,WAAKJ,UAAU,MAAM,KAAKO,WAAU;IACtC;EACF;;;;;;;;;;;;;;;;;;EAmBA,MAAcA,WAAWC,UAA6B,CAAC,GAAG;AACxD,QAAIC;AACJ,QAAIC,OAAO;AAGX,aAASP,QAAQ,KAAKF,OAAO;AAC3B,YAAMU,SAASC,cAAcT,KAAKU,MAAM,KAAKV,KAAKW,EAAE;AACpD,UAAIH,QAAQ;AACVF,mBAAW,IAAIN,KAAK,KAAKA,MAAMQ,MAAAA;AAC/B;MACF;IACF;AAEA,QAAI,CAACF,UAAU;AACb,YAAM,IAAIM,MAAM,gBAAA;IAClB;AAIA,UAAMC,aAAa,mCAAA;AACjB,YAAMC,OAAO,MAAM,KAAKd,KAAKe,QAAQC,IAAI,GAAA;AACzC,YAAMC,SAAS,MAAM,KAAKjB,KAAKe,QAAQG,KAAI;AAC3C,YAAMC,YAAiBL,QAAQ,CAAC;AAChC,eAAS,CAACM,KAAK1B,KAAAA,KAAUuB,QAAQ;AAC/B,YAAIG,OAAO,KAAK;AACd;QACF;AACAC,QAAAA,MAAKF,WAAWC,KAAK1B,KAAAA;MACvB;AACA4B,WAAKhB,UAAUa,SAAAA;IACjB,GAXmB;AAanB,UAAMN,WAAAA;AAENP,aAASiB,aAAa,CAAC;AAGvB,UAAMC,SAAS,wBAACC,WAAAA;AACd,UAAIpB,QAAQqB,cAAc;AACxBC,oBAAYF,QAAQnB,SAASiB,UAAU;MACzC;AACA,UAAIhB,QAAQ,KAAKN,aAAa;AAC5BM,eAAO;AACP;MACF;AACA,YAAMqB,SAASD,YAAYF,QAAQnB,SAASiB,UAAU;AACtD,WAAKvB,KAAK6B,UACRC,KAAKC,UAAU;QACbC,MAAM;QACNtC,OAAOkC;MACT,CAAA,CAAA;AAEFH,aAAOQ,MAAK;IACd,GAhBe;AAmBf,UAAMC,YAAY,8BAAOT,WAAAA;AACvB,eAASf,QAAQe,QAAQ;AACvB,cAAMU,YACJzB,QAAQ,MAAMJ,WAAW8B,UAAU9B,UAAUI,IAAAA;AAC/C,cAAM2B,YAAYC,qBAAqBH,SAAAA;AACvC,cAAM,KAAKnC,KAAKe,QAAQwB,IAAI7B,MAAM2B,SAAAA;MACpC;AACAZ,aAAOQ,MAAK;IACd,GARkB;AAWlBO,cAAUlC,UAAU;MAClBmC,QAAQC,SAASlB,QAAQlB,SAAS,cAAA,KAAmB,GAAA;MACrDqC,WAAWD,SAASR,WAAW5B,SAAS,iBAAA,KAAsB,GAAA;IAChE,CAAA;AAEA,WAAOA;EACT;;;;;;;;;;;;;;;;;EAkBA,MAAcsC,WAAWvC,UAAU,CAAC,GAAG;AACrC,QAAIR;AACJ,QAAI,KAAKI,aAAa;AACpBJ,gBAAU,MAAM,KAAKO,WAAWC,OAAAA;IAClC,OACK;AACHR,gBAAU,KAAKA;IACjB;AACA,WAAOA;EACT;;;;;;;;;;;;;;;;EAkBQgD,iBAAiBhD,SAAS;AAChC,UAAMiD,OAAOjD,QAAQE,YAAY,mBAAA;AACjC,UAAMgD,SAASD,MAAM9B,IAAI,OAAA;AACzB,QAAI+B,QAAQ;AACV,aAAOlD,QAAQkD,MAAAA;IACjB;AACA,WAAO;EACT;;;;;;;;;;;;;;;;;EAkBA,MAAMC,UAAUC,MAAwBC,KAA8B;AACpE,UAAMrD,UAAU,MAAM,KAAK+C,WAAW;MACpClB,cAAc;IAChB,CAAA;AAEA,UAAMyB,WAAWC,kBAAAA;AACjB,QAAIC,OAAO;AACX,UAAMC,SAAS,KAAKT,iBAAiBhD,OAAAA;AACrC,QAAIyD,QAAQ;AACV,YAAM,EAAEC,UAAS,IAAKD,OAAOjD;AAE7BgD,aAAOG,SAAQD,SAAAA,IAAa,IAAIA,UAAAA,IAAcA,UAAUN,MAAMC,GAAAA;AAC9DI,aAAAA,EAASH,QAAAA,IAAYE;IACvB;AAEA,UAAMI,YAAY5D,QAAQ,QAAA,IAAYwD,MAAMJ,MAAMC,GAAAA,CAAAA;AAClDD,SAAKS,SAAS;MAAEP;IAAS,CAAA;AAEzBF,SAAKU,KACH7B,KAAKC,UAAU;MACbC,MAAM;MACNtC,OAAO;QACLkE,KAAKT;QACL,GAAGtD,QAAQ0B;MACb;IACF,CAAA,CAAA;EAEJ;;;;;;;;;;;;;;;;;EAmBA,MAAMsC,UAAUC,SAAiBC,QAA0B;AACzD,QAAIC;AACJ,QAAI;AACFA,aAAOlC,KAAKmC,MAAMH,OAAAA;IACpB,SACOI,GAAG;AACR;IACF;AAEA,UAAMC,SAAS9E,QAAQ+E,UAAUJ,IAAAA;AACjC,QAAI,CAACG,OAAOE,SAAS;AACnB;IACF;AACA,UAAMxE,UAAU,MAAM,KAAK+C,WAAU;AACrC,UAAM0B,UAAUzE,QAAQE,YAAY,iBAAA;AACpC,QAAIuE,SAAS;AACX,YAAMhB,SAAS,KAAKT,iBAAiBhD,OAAAA;AACrC,YAAM,EAAEsD,SAAQ,IAAKY,OAAOQ;AAC5B,YAAMlB,OAAOC,SAAAA,EAAWH,QAAAA;AACxB,YAAMqB,aAAaF,QAAQtD,IAAImD,OAAOM,KAAKjF,MAAM;AACjD,UAAIgF,YAAY;AAEd,YAAIA,WAAWE,gBAAgB;AAC7B,gBAAMC,aAAaH,WAAWE,eAAeN,UAC3CD,OAAOM,KAAK/E,KAAK;AAEnB,cAAI,CAACiF,WAAWN,SAAS;AACvB;UACF;QACF;AAEA,cAAMZ,YACJ5D,QAAQ2E,WAAWpD,GAAG,EAAEiC,MAAMc,OAAOM,KAAK/E,OAAOqE,MAAAA,CAAAA;MAErD;IACF;EACF;;;;;;;;;;;;;;;;EAiBA,MAAMa,QAAQ3B,MAAwB;AACpC,UAAMpD,UAAU,MAAM,KAAK+C,WAAU;AACrC,UAAMU,SAAS,KAAKT,iBAAiBhD,OAAAA;AACrC,UAAM,EAAEsD,SAAQ,IAAKF,KAAKsB;AAC1B,UAAMlB,OAAOC,SAAAA,EAAWH,QAAAA;AAExB,UAAMM,YAAY5D,QAAQ,SAAA,IAAawD,MAAMJ,IAAAA,CAAAA;AAC7C,QAAIK,QAAQ;AAEV,aAAOA,OAAAA,EAASH,QAAAA;IAClB;EACF;AACF;","names":["Action","name","bodyValidation","target","propertyKey","constructor","_actionMetadata","Map","set","key","Room","options","path","maxUsers","throttleStorage","throttleSync","isClass","obj","prototype","constructor","isObject","item","Array","isArray","generateShortUUID","chars","uuid","i","randomIndex","Math","floor","random","length","MockPartySocket","events","Map","id","generateShortUUID","addEventListener","event","cb","set","removeEventListener","delete","_trigger","data","get","MockStorage","storage","key","put","value","list","MockPartyRoom","clients","constructor","connection","client","socket","broadcast","forEach","clear","MockConnection","state","setState","ServerIo","ClientIo","dset","z","ArraySubject","ObjectSubject","isSignal","syncClass","instance","options","cacheSync","Map","cachePersist","Set","$valuesChanges","set","path","value","onSync","setPersist","add","onPersist","has","get","createSyncClass","createStatesSnapshot","persistObject","$snapshot","key","keys","signal","persist","isObject","Array","isArray","setMetadata","target","meta","constructor","_propertyMetadata","propId","isSignal","currentClass","parentKey","parentClass","$path","syncToClient","newPath","isSignal","load","rootInstance","values","valueIsObject","loadFromObject","loadFromPaths","path","value","Object","entries","parts","split","loadValue","currentPath","key","newPath","Array","isArray","current","i","length","part","isSignal","Reflect","deleteProperty","_subject","set","currentValue","undefined","parentInstance","getByPath","slice","join","classType","options","isClass","setMetadata","root","dset","isPromise","value","Promise","awaitReturn","val","isClass","obj","prototype","constructor","throttle","func","wait","timeout","lastArgs","args","setTimeout","extractParams","pattern","str","regexPattern","replace","regex","RegExp","match","exec","groups","dremove","keys","split","i","l","length","t","k","buildObject","valuesMap","allMemory","memoryObj","path","get","dset","Message","z","object","action","string","value","any","Server","subRoom","rooms","constructor","room","isHibernate","hibernate","onStart","createRoom","options","instance","init","params","extractParams","path","id","Error","loadMemory","root","storage","get","memory","list","tmpObject","key","dset","load","$memoryAll","syncCb","values","getMemoryAll","buildObject","packet","broadcast","JSON","stringify","type","clear","persistCb","_instance","getByPath","itemValue","createStatesSnapshot","put","syncClass","onSync","throttle","onPersist","getSubRoom","getUsersProperty","meta","propId","onConnect","conn","ctx","publicId","generateShortUUID","user","signal","classType","isClass","awaitReturn","setState","send","pId","onMessage","message","sender","json","parse","e","result","safeParse","success","actions","state","actionName","data","bodyValidation","bodyResult","onClose"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signe/room",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"keywords": [],
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"dset": "^3.1.3",
|
|
18
18
|
"partysocket": "^1.0.1",
|
|
19
19
|
"zod": "^3.23.8",
|
|
20
|
-
"@signe/sync": "1.0.
|
|
20
|
+
"@signe/sync": "1.0.2"
|
|
21
21
|
},
|
|
22
22
|
"publishConfig": {
|
|
23
23
|
"access": "public"
|