@rbxts/replion 1.0.10 → 1.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/Client.lua +34 -16
- package/src/Server.lua +25 -19
- package/src/Shared.lua +5 -0
- package/src/index.d.ts +31 -12
package/README.md
CHANGED
package/package.json
CHANGED
package/src/Client.lua
CHANGED
|
@@ -58,29 +58,45 @@ function Client.new(channel: string, data: Shared.GenericDataTable)
|
|
|
58
58
|
return self;
|
|
59
59
|
end;
|
|
60
60
|
|
|
61
|
-
function Client:get(
|
|
62
|
-
if not
|
|
63
|
-
|
|
64
|
-
return Shared.getNestedValue(self.data, key);
|
|
65
|
-
end;
|
|
66
|
-
|
|
67
|
-
return self.data[key];
|
|
61
|
+
function Client:get(path: { string }?)
|
|
62
|
+
if not path then return self.data; end;
|
|
63
|
+
return Shared.getNestedValue(self.data, path);
|
|
68
64
|
end;
|
|
69
65
|
|
|
70
|
-
function Client:observe(
|
|
71
|
-
if not
|
|
66
|
+
function Client:observe(path: { string }?, callback: Observer)
|
|
67
|
+
if not path then
|
|
72
68
|
task.spawn(callback, self.data, nil);
|
|
73
|
-
|
|
74
69
|
return self._allSignal:Connect(callback);
|
|
75
70
|
end;
|
|
76
71
|
|
|
77
|
-
|
|
78
|
-
|
|
72
|
+
local signalKey = Shared.getSignalKey(path);
|
|
73
|
+
if not self._signals[signalKey] then
|
|
74
|
+
self._signals[signalKey] = Signal.new();
|
|
79
75
|
end;
|
|
80
76
|
|
|
81
|
-
|
|
77
|
+
local initialValue = Shared.getNestedValue(self.data, path);
|
|
82
78
|
|
|
83
|
-
|
|
79
|
+
task.spawn(callback, initialValue, nil);
|
|
80
|
+
return self._signals[signalKey]:Connect(callback);
|
|
81
|
+
end;
|
|
82
|
+
|
|
83
|
+
function Client:_recursiveSignalCheck(currentPath: { string }, updateTree: any)
|
|
84
|
+
for k, v in updateTree do
|
|
85
|
+
local nextPath = table.clone(currentPath);
|
|
86
|
+
table.insert(nextPath, k);
|
|
87
|
+
|
|
88
|
+
local signalKey = Shared.getSignalKey(nextPath);
|
|
89
|
+
local signal = self._signals[signalKey];
|
|
90
|
+
|
|
91
|
+
if signal then
|
|
92
|
+
local newValue = Shared.getNestedValue(self.data, nextPath);
|
|
93
|
+
signal:Fire(newValue, newValue); -- Warning: Sends improper 'old' argument due to shallow copy optimization.
|
|
94
|
+
end;
|
|
95
|
+
|
|
96
|
+
if typeof(v) == 'table' then
|
|
97
|
+
self:_recursiveSignalCheck(nextPath, v);
|
|
98
|
+
end;
|
|
99
|
+
end;
|
|
84
100
|
end;
|
|
85
101
|
|
|
86
102
|
function Client:_applyUpdates(updates: Shared.GenericDataTable)
|
|
@@ -93,13 +109,15 @@ function Client:_applyUpdates(updates: Shared.GenericDataTable)
|
|
|
93
109
|
for key, newValue in updates do
|
|
94
110
|
local oldValue = oldData[key];
|
|
95
111
|
|
|
96
|
-
-- If it's a table, we assume it changed if it's in the
|
|
112
|
+
-- If it's a table, we assume it changed if it's in the updates list.
|
|
97
113
|
if typeof(newValue) == 'table' then
|
|
98
114
|
anyChanged = true
|
|
99
115
|
local signal = self._signals[key];
|
|
100
116
|
if signal then
|
|
101
117
|
signal:Fire(self.data[key], self.data[key]); -- Warning: Sends improper 'old' argument due to shallow copy optimization.
|
|
102
118
|
end;
|
|
119
|
+
|
|
120
|
+
self:_recursiveSignalCheck({key}, newValue);
|
|
103
121
|
elseif self.data[key] ~= oldValue then
|
|
104
122
|
anyChanged = true;
|
|
105
123
|
local signal = self._signals[key];
|
|
@@ -126,7 +144,7 @@ remote.OnClientEvent:Connect(function(type, channel, payload)
|
|
|
126
144
|
if type == 'I' then
|
|
127
145
|
local newReplion = Client.new(channel, payload);
|
|
128
146
|
Client._activeReplions[channel] = newReplion;
|
|
129
|
-
|
|
147
|
+
|
|
130
148
|
local initializedSignal = Client._replionInitializedSignals[channel];
|
|
131
149
|
if not initializedSignal then return; end;
|
|
132
150
|
|
package/src/Server.lua
CHANGED
|
@@ -99,24 +99,26 @@ function Server.new(config: ServerConfig)
|
|
|
99
99
|
return self;
|
|
100
100
|
end;
|
|
101
101
|
|
|
102
|
-
function Server:observe(
|
|
103
|
-
if not
|
|
102
|
+
function Server:observe(path: { string }?, callback: Observer)
|
|
103
|
+
if not path then
|
|
104
104
|
task.spawn(callback, self.data, nil);
|
|
105
105
|
return self._allSignal:Connect(callback);
|
|
106
106
|
end;
|
|
107
107
|
|
|
108
|
-
|
|
109
|
-
|
|
108
|
+
local signalKey = Shared.getSignalKey(path);
|
|
109
|
+
if not self._signals[signalKey] then
|
|
110
|
+
self._signals[signalKey] = Signal.new();
|
|
110
111
|
end;
|
|
111
112
|
|
|
112
|
-
|
|
113
|
-
|
|
113
|
+
local initialValue = Shared.getNestedValue(self.data, path);
|
|
114
|
+
|
|
115
|
+
task.spawn(callback, initialValue, nil);
|
|
116
|
+
return self._signals[signalKey]:Connect(callback);
|
|
114
117
|
end;
|
|
115
118
|
|
|
116
|
-
function Server:set(
|
|
119
|
+
function Server:set(path: { string }, value: any)
|
|
117
120
|
if self._destroyed then return; end;
|
|
118
121
|
|
|
119
|
-
local path = if typeof(key) == 'table' then key else {key};
|
|
120
122
|
local topKey = path[1];
|
|
121
123
|
|
|
122
124
|
local oldValue = Shared.getNestedValue(self.data, path);
|
|
@@ -130,9 +132,17 @@ function Server:set(key: string | {string}, value: any)
|
|
|
130
132
|
self:_scheduleUpdatesFlush();
|
|
131
133
|
|
|
132
134
|
do
|
|
133
|
-
local
|
|
134
|
-
if
|
|
135
|
-
|
|
135
|
+
local topSignal = self._signals[topKey];
|
|
136
|
+
if topSignal then
|
|
137
|
+
topSignal:Fire(self.data[topKey], oldTop);
|
|
138
|
+
end;
|
|
139
|
+
|
|
140
|
+
local signalKey = Shared.getSignalKey(path);
|
|
141
|
+
if signalKey ~= topKey then
|
|
142
|
+
local pathSignal = self._signals[signalKey];
|
|
143
|
+
if pathSignal then
|
|
144
|
+
pathSignal:Fire(newValue, oldValue)
|
|
145
|
+
end;
|
|
136
146
|
end;
|
|
137
147
|
|
|
138
148
|
local thisUpdate = {};
|
|
@@ -141,13 +151,9 @@ function Server:set(key: string | {string}, value: any)
|
|
|
141
151
|
end;
|
|
142
152
|
end;
|
|
143
153
|
|
|
144
|
-
function Server:get(
|
|
145
|
-
if not
|
|
146
|
-
|
|
147
|
-
return Shared.getNestedValue(self.data, key);
|
|
148
|
-
end;
|
|
149
|
-
|
|
150
|
-
return self.data[key];
|
|
154
|
+
function Server:get(path: { string }?)
|
|
155
|
+
if not path then return self.data; end;
|
|
156
|
+
return Shared.getNestedValue(self.data, path);
|
|
151
157
|
end;
|
|
152
158
|
|
|
153
159
|
function Server:destroy()
|
|
@@ -230,4 +236,4 @@ Players.PlayerRemoving:Connect(function(player)
|
|
|
230
236
|
Server._activeReplions[player] = nil;
|
|
231
237
|
end);
|
|
232
238
|
|
|
233
|
-
return Server;
|
|
239
|
+
return Server;
|
package/src/Shared.lua
CHANGED
|
@@ -15,4 +15,9 @@ function Shared.getNestedValue(root: any, path: { string })
|
|
|
15
15
|
return current;
|
|
16
16
|
end;
|
|
17
17
|
|
|
18
|
+
function Shared.getSignalKey(key: string | { string })
|
|
19
|
+
if typeof(key) == 'string' then return key; end;
|
|
20
|
+
return table.concat(key, '\0');
|
|
21
|
+
end;
|
|
22
|
+
|
|
18
23
|
return Shared;
|
package/src/index.d.ts
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
import { Connection } from '@rbxts/sleitnick-signal';
|
|
2
2
|
|
|
3
3
|
declare namespace Replion {
|
|
4
|
+
/**
|
|
5
|
+
* Recursively builds a union of all valid path tuples for object T.
|
|
6
|
+
* E.g., { a: { b: 1 } } -> ['a'] | ['a', 'b']
|
|
7
|
+
*/
|
|
8
|
+
type Path<T> = T extends object
|
|
9
|
+
? { [K in keyof T & string]: [K] | [K, ...Path<T[K]>] }[keyof T & string]
|
|
10
|
+
: never;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Resolves the type of the value at a specific path P within object T.
|
|
14
|
+
*/
|
|
15
|
+
type PathValue<T, P extends any[]> = P extends [infer K, ...infer R]
|
|
16
|
+
? K extends keyof T
|
|
17
|
+
? R extends []
|
|
18
|
+
? T[K]
|
|
19
|
+
: PathValue<T[K], R>
|
|
20
|
+
: never
|
|
21
|
+
: never;
|
|
22
|
+
|
|
4
23
|
interface ServerConfig<T extends object> {
|
|
5
24
|
channel: string;
|
|
6
25
|
replicateTo?: Player;
|
|
@@ -10,17 +29,18 @@ declare namespace Replion {
|
|
|
10
29
|
class Server<T extends object> {
|
|
11
30
|
constructor(config: ServerConfig<T>);
|
|
12
31
|
|
|
13
|
-
set<
|
|
14
|
-
|
|
32
|
+
set<P extends Path<T>>(
|
|
33
|
+
path: P,
|
|
34
|
+
value: PathValue<T, P> | ((oldValue: PathValue<T, P>) => PathValue<T, P>),
|
|
35
|
+
): void;
|
|
15
36
|
|
|
16
37
|
get(): T;
|
|
17
|
-
get<
|
|
18
|
-
get(path: string[]): any;
|
|
38
|
+
get<P extends Path<T>>(path: P): PathValue<T, P>;
|
|
19
39
|
|
|
20
40
|
observe(key: undefined, callback: (newValue: T, oldValue: Partial<T>) => void): Connection;
|
|
21
|
-
observe<
|
|
22
|
-
|
|
23
|
-
callback: (newValue: T
|
|
41
|
+
observe<P extends Path<T>>(
|
|
42
|
+
path: P,
|
|
43
|
+
callback: (newValue: PathValue<T, P>, oldValue: PathValue<T, P> | undefined) => void,
|
|
24
44
|
): Connection;
|
|
25
45
|
|
|
26
46
|
destroy(): void;
|
|
@@ -30,13 +50,12 @@ declare namespace Replion {
|
|
|
30
50
|
static waitForReplion: <T extends object>(channel: string) => Client<T>;
|
|
31
51
|
|
|
32
52
|
get(): T;
|
|
33
|
-
get<
|
|
34
|
-
get(path: string[]): any;
|
|
53
|
+
get<P extends Path<T>>(path: P): PathValue<T, P>;
|
|
35
54
|
|
|
36
55
|
observe(key: undefined, callback: (newValue: T, oldValue: Partial<T>) => void): Connection;
|
|
37
|
-
observe<
|
|
38
|
-
|
|
39
|
-
callback: (newValue: T
|
|
56
|
+
observe<P extends Path<T>>(
|
|
57
|
+
path: P,
|
|
58
|
+
callback: (newValue: PathValue<T, P>, oldValue: PathValue<T, P> | undefined) => void,
|
|
40
59
|
): Connection;
|
|
41
60
|
|
|
42
61
|
destroy(): void;
|