@rbxts/tether 1.2.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,28 +24,26 @@ export interface MessageData {
24
24
  readonly n: DataType.u8;
25
25
  };
26
26
  [Message.Packed]: DataType.Packed<{
27
- boolean1: boolean;
28
- boolean2: boolean;
29
- boolean3: boolean;
30
- boolean4: boolean;
31
- boolean5: boolean;
32
- boolean6: boolean;
33
- boolean7: boolean;
34
- boolean8: boolean;
27
+ readonly boolean1: boolean;
28
+ readonly boolean2: boolean;
29
+ readonly boolean3: boolean;
30
+ readonly boolean4: boolean;
31
+ readonly boolean5: boolean;
32
+ readonly boolean6: boolean;
33
+ readonly boolean7: boolean;
34
+ readonly boolean8: boolean;
35
35
  }>;
36
36
  }
37
37
  ```
38
38
 
39
39
  > [!CAUTION]
40
- > Every single message kind must implement an interface for it's data (in the example that would be the object with the `foo` and `bar` fields). Message serialization (as well as your message itself) will not work if you don't do this.
40
+ > Every single message kind must implement an interface for it's data (in the example that would be the object types in `MessageData`). Message serialization (as well as your message itself) will not work if you don't do this.
41
41
 
42
42
  ### Server
43
43
  ```ts
44
44
  import { Message, messaging } from "shared/messaging";
45
45
 
46
- messaging.server.on(Message.Test, (player, data) => {
47
- print(player, "sent data:", data);
48
- });
46
+ messaging.server.on(Message.Test, (player, data) => print(player, "sent data:", data));
49
47
  ```
50
48
 
51
49
  ### Client
@@ -116,7 +114,7 @@ Drop, delay, or modify requests
116
114
  import type { ClientMiddleware } from "@rbxts/tether";
117
115
 
118
116
  export function logClient(): ClientMiddleware {
119
- return message => (player, data) => print(`[LOG]: Sent message '${message}' to player ${player} with data:`, data);
117
+ return message => (player, ctx) => print(`[LOG]: Sent message '${message}' to player ${player} with data:`, ctx.data);
120
118
  }
121
119
  ```
122
120
 
@@ -125,7 +123,7 @@ export function logClient(): ClientMiddleware {
125
123
  import type { ServerMiddleware } from "@rbxts/tether";
126
124
 
127
125
  export function logServer(): ServerMiddleware {
128
- return message => data => print(`[LOG]: Sent message '${message}' to server with data:`, data);
126
+ return message => ctx => print(`[LOG]: Sent message '${message}' to server with data:`, ctx.data);
129
127
  }
130
128
  ```
131
129
 
@@ -152,7 +150,7 @@ import type { ServerMiddleware } from "@rbxts/tether";
152
150
 
153
151
  export function incrementNumberData(): ServerMiddleware<number> {
154
152
  // sets the data to be used by the any subsequent middlewares as well as sent through the remote
155
- return () => (data, updateData) => updateData(data + 1);
153
+ return () => ({ data, updateData }) => updateData(data + 1);
156
154
  }
157
155
  ```
158
156
 
@@ -166,7 +164,8 @@ messaging.middleware
166
164
  // only allows requests to the server every 5 seconds,
167
165
  // drops any requests that occur within 5 seconds of each other
168
166
  .useServer(Message.Test, BuiltinMiddlewares.rateLimit(5))
169
- .useShared(Message.Packed, () => (_, __, getRawData) => print("Packed object size:", buffer.len(getRawData()))); // will be just one byte!
167
+ // will be just one byte!
168
+ .useShared(Message.Packed, () => ctx => print("Packed object size:", buffer.len(ctx.getRawData().buffer)));
170
169
  // logs every message fired
171
170
  .useServerGlobal(logServer())
172
171
  .useClientGlobal(logClient())
@@ -185,14 +184,14 @@ export interface MessageData {
185
184
  readonly n: DataType.u8;
186
185
  };
187
186
  [Message.Packed]: DataType.Packed<{
188
- boolean1: boolean;
189
- boolean2: boolean;
190
- boolean3: boolean;
191
- boolean4: boolean;
192
- boolean5: boolean;
193
- boolean6: boolean;
194
- boolean7: boolean;
195
- boolean8: boolean;
187
+ readonly boolean1: boolean;
188
+ readonly boolean2: boolean;
189
+ readonly boolean3: boolean;
190
+ readonly boolean4: boolean;
191
+ readonly boolean5: boolean;
192
+ readonly boolean6: boolean;
193
+ readonly boolean7: boolean;
194
+ readonly boolean8: boolean;
196
195
  }>;
197
196
  }
198
197
  ```
@@ -11,6 +11,14 @@ export declare namespace BuiltinMiddlewares {
11
11
  * @returns A shared middleware that will simulate a ping
12
12
  */
13
13
  function simulatePing(pingInMs: number): SharedMiddleware;
14
+ /**
15
+ * Creates a shared middleware that will check if a message packet exceeds the given maximum size in bytes
16
+ *
17
+ * @param maxBytes The maximum size of the packet in bytes
18
+ * @param throwError Whether the middleware should throw an error if the packet exceeds the maximum size, or simply drop the request
19
+ * @returns A shared middleware that will check if a message packet exceeds the given maximum size
20
+ */
21
+ function maxPacketSize(maxBytes: number, throwError?: boolean): SharedMiddleware;
14
22
  /**
15
23
  * Creates a shared middleware that will drop any message that occurs within the given interval of the previous message
16
24
  *
@@ -24,6 +24,30 @@ do
24
24
  end
25
25
  end
26
26
  _container.simulatePing = simulatePing
27
+ --[[
28
+ *
29
+ * Creates a shared middleware that will check if a message packet exceeds the given maximum size in bytes
30
+ *
31
+ * @param maxBytes The maximum size of the packet in bytes
32
+ * @param throwError Whether the middleware should throw an error if the packet exceeds the maximum size, or simply drop the request
33
+ * @returns A shared middleware that will check if a message packet exceeds the given maximum size
34
+
35
+ ]]
36
+ local function maxPacketSize(maxBytes, throwError)
37
+ if throwError == nil then
38
+ throwError = true
39
+ end
40
+ return function(message)
41
+ return function(ctx)
42
+ local rawData = ctx.getRawData()
43
+ local totalSize = buffer.len(rawData.buffer) + #rawData.blobs * BLOB_SIZE
44
+ if totalSize > maxBytes then
45
+ return if throwError then error(`[@rbxts/tether]: Message '{message}' exceeded maximum packet size of {maxBytes} bytes`) else DropRequest
46
+ end
47
+ end
48
+ end
49
+ end
50
+ _container.maxPacketSize = maxPacketSize
27
51
  --[[
28
52
  *
29
53
  * Creates a shared middleware that will drop any message that occurs within the given interval of the previous message
@@ -87,7 +111,9 @@ do
87
111
  ]]
88
112
  local function debug(schema)
89
113
  return function(message)
90
- return function(data, _, getRawData)
114
+ return function(_param)
115
+ local data = _param.data
116
+ local getRawData = _param.getRawData
91
117
  local rawData = getRawData()
92
118
  local bufferSize = buffer.len(rawData.buffer)
93
119
  local blobsSize = #rawData.blobs * BLOB_SIZE
@@ -9,7 +9,7 @@ export declare class MessageEmitter<MessageData> extends Destroyable {
9
9
  private readonly serverCallbacks;
10
10
  private readonly serverFunctions;
11
11
  private readonly guards;
12
- private serializers;
12
+ private readonly serializers;
13
13
  private serverEvents;
14
14
  private clientEvents;
15
15
  /** @metadata macro */
@@ -61,11 +61,16 @@ do
61
61
  return nil
62
62
  end
63
63
  task.spawn(function()
64
+ local ctx = {
65
+ data = data,
66
+ updateData = updateData,
67
+ getRawData = getPacket,
68
+ }
64
69
  for _, globalMiddleware in self.middleware:getServerGlobal() do
65
70
  if not self:validateData(message, data) then
66
71
  return nil
67
72
  end
68
- local result = globalMiddleware(message)(data, updateData, getPacket)
73
+ local result = globalMiddleware(message)(ctx)
69
74
  if result == DropRequest then
70
75
  return nil
71
76
  end
@@ -74,7 +79,7 @@ do
74
79
  if not self:validateData(message, data) then
75
80
  return nil
76
81
  end
77
- local result = middleware(message)(data, updateData, getPacket)
82
+ local result = middleware(message)(ctx)
78
83
  if result == DropRequest then
79
84
  return nil
80
85
  end
@@ -140,11 +145,16 @@ do
140
145
  return nil
141
146
  end
142
147
  task.spawn(function()
148
+ local ctx = {
149
+ data = data,
150
+ updateData = updateData,
151
+ getRawData = getPacket,
152
+ }
143
153
  for _, globalMiddleware in self.middleware:getClientGlobal() do
144
154
  if not self:validateData(message, data) then
145
155
  return nil
146
156
  end
147
- local result = globalMiddleware(message)(player, data, updateData, getPacket)
157
+ local result = globalMiddleware(message)(player, ctx)
148
158
  if result == DropRequest then
149
159
  return nil
150
160
  end
@@ -153,7 +163,7 @@ do
153
163
  if not self:validateData(message, data) then
154
164
  return nil
155
165
  end
156
- local result = middleware(message)(player, data, updateData, getPacket)
166
+ local result = middleware(message)(player, ctx)
157
167
  if result == DropRequest then
158
168
  return nil
159
169
  end
@@ -180,12 +190,17 @@ do
180
190
  return nil
181
191
  end
182
192
  task.spawn(function()
193
+ local ctx = {
194
+ data = data,
195
+ updateData = updateData,
196
+ getRawData = getPacket,
197
+ }
183
198
  for _, globalMiddleware in self.middleware:getClientGlobal() do
184
199
  for _1, player in Players:GetPlayers() do
185
200
  if not self:validateData(message, data) then
186
201
  return nil
187
202
  end
188
- local result = globalMiddleware(message)(player, data, updateData, getPacket)
203
+ local result = globalMiddleware(message)(player, ctx)
189
204
  if result == DropRequest then
190
205
  return nil
191
206
  end
@@ -196,7 +211,7 @@ do
196
211
  if not self:validateData(message, data) then
197
212
  return nil
198
213
  end
199
- local result = middleware(message)(player, data, updateData, getPacket)
214
+ local result = middleware(message)(player, ctx)
200
215
  if result == DropRequest then
201
216
  return nil
202
217
  end
@@ -244,7 +259,7 @@ do
244
259
  self.janitor:Add(function()
245
260
  table.clear(self.clientCallbacks)
246
261
  table.clear(self.serverCallbacks)
247
- self.serializers = nil
262
+ table.clear(self.serializers)
248
263
  self.serverEvents = nil
249
264
  self.clientEvents = nil
250
265
  end)
@@ -3,16 +3,19 @@ type DropRequestSymbol = symbol & {
3
3
  _drop_req?: undefined;
4
4
  };
5
5
  export declare const DropRequest: DropRequestSymbol;
6
- type UpdateDataFn<T> = (newData: T) => void;
7
- type GetRawDataFn = () => SerializedPacket;
8
6
  export type ClientMiddleware<Data = unknown> = {
9
7
  _client?: void;
10
- } & ((message: BaseMessage) => (player: Player | Player[], data: Readonly<Data>, updateData: UpdateDataFn<Data>, getRawData: GetRawDataFn) => DropRequestSymbol | void);
11
- export type ServerMiddleware<Data = unknown> = SharedMiddleware<Data> & {
8
+ } & ((message: BaseMessage) => (player: Player | Player[], ctx: MiddlewareContext<Data>) => DropRequestSymbol | void);
9
+ export type ServerMiddleware<Data = unknown> = {
12
10
  _server?: void;
13
- };
14
- export type SharedMiddleware<Data = unknown> = (message: BaseMessage) => (data: Readonly<Data>, updateData: UpdateDataFn<Data>, getRawData: GetRawDataFn) => DropRequestSymbol | void;
11
+ } & SharedMiddleware<Data>;
12
+ export type SharedMiddleware<Data = unknown> = (message: BaseMessage) => (ctx: MiddlewareContext<Data>) => DropRequestSymbol | void;
15
13
  export type Middleware<Data = unknown> = ServerMiddleware<Data> & ClientMiddleware<Data> & SharedMiddleware<Data>;
14
+ export interface MiddlewareContext<Data = unknown> {
15
+ readonly data: Readonly<Data>;
16
+ updateData: (newData: Data) => void;
17
+ getRawData: () => SerializedPacket;
18
+ }
16
19
  export declare class MiddlewareProvider<MessageData> {
17
20
  private readonly clientGlobalMiddlewares;
18
21
  private readonly serverGlobalMiddlewares;
@@ -78,8 +78,8 @@ do
78
78
  local _newValue = table.create(#_exp)
79
79
  local _callback = function(middleware)
80
80
  return function(message)
81
- return function(_, data, updateData, getRawData)
82
- return middleware(message)(data, updateData, getRawData)
81
+ return function(_, ctx)
82
+ return middleware(message)(ctx)
83
83
  end
84
84
  end
85
85
  end
@@ -133,8 +133,8 @@ do
133
133
  local _newValue = table.create(#_exp)
134
134
  local _callback = function(middleware)
135
135
  return function(message)
136
- return function(_, data, updateData, getRawData)
137
- return middleware(message)(data, updateData, getRawData)
136
+ return function(_, ctx)
137
+ return middleware(message)(ctx)
138
138
  end
139
139
  end
140
140
  end
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rbxts/tether",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "main": "out/init.lua",
5
5
  "scripts": {
6
6
  "build": "rbxtsc",