@flamework-experimental/networking 2.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +66 -0
  2. package/flamework.build +7 -0
  3. package/out/event/createEvent.d.ts +59 -0
  4. package/out/event/createEvent.luau +114 -0
  5. package/out/event/createRemoteInstance.d.ts +1 -0
  6. package/out/event/createRemoteInstance.luau +58 -0
  7. package/out/events/createClientMethod.d.ts +5 -0
  8. package/out/events/createClientMethod.luau +30 -0
  9. package/out/events/createGenericHandler.d.ts +5 -0
  10. package/out/events/createGenericHandler.luau +102 -0
  11. package/out/events/createNetworkingEvent.d.ts +2 -0
  12. package/out/events/createNetworkingEvent.luau +60 -0
  13. package/out/events/createServerMethod.d.ts +13 -0
  14. package/out/events/createServerMethod.luau +63 -0
  15. package/out/events/types.d.ts +220 -0
  16. package/out/function/createFunctionReceiver.d.ts +52 -0
  17. package/out/function/createFunctionReceiver.luau +118 -0
  18. package/out/function/createFunctionSender.d.ts +45 -0
  19. package/out/function/createFunctionSender.luau +135 -0
  20. package/out/function/errors.d.ts +10 -0
  21. package/out/function/errors.luau +25 -0
  22. package/out/functions/createClientMethod.d.ts +15 -0
  23. package/out/functions/createClientMethod.luau +52 -0
  24. package/out/functions/createGenericHandler.d.ts +7 -0
  25. package/out/functions/createGenericHandler.luau +140 -0
  26. package/out/functions/createNetworkingFunction.d.ts +2 -0
  27. package/out/functions/createNetworkingFunction.luau +68 -0
  28. package/out/functions/createServerMethod.d.ts +15 -0
  29. package/out/functions/createServerMethod.luau +52 -0
  30. package/out/functions/types.d.ts +289 -0
  31. package/out/handlers.d.ts +36 -0
  32. package/out/index.d.ts +55 -0
  33. package/out/init.luau +78 -0
  34. package/out/middleware/createGuardMiddleware.d.ts +6 -0
  35. package/out/middleware/createGuardMiddleware.luau +44 -0
  36. package/out/middleware/createMiddlewareProcessor.d.ts +3 -0
  37. package/out/middleware/createMiddlewareProcessor.luau +24 -0
  38. package/out/middleware/skip.d.ts +8 -0
  39. package/out/middleware/skip.luau +22 -0
  40. package/out/middleware/types.d.ts +15 -0
  41. package/out/types.d.ts +78 -0
  42. package/out/util/createSignalContainer.d.ts +5 -0
  43. package/out/util/createSignalContainer.luau +30 -0
  44. package/out/util/getNamespaceConfig.d.ts +10 -0
  45. package/out/util/getNamespaceConfig.luau +15 -0
  46. package/out/util/timeoutPromise.d.ts +1 -0
  47. package/out/util/timeoutPromise.luau +10 -0
  48. package/package.json +32 -0
@@ -0,0 +1,220 @@
1
+ import {
2
+ FunctionParameters,
3
+ IntrinsicTupleGuards,
4
+ IntrinsicNetworkDecoder,
5
+ IntrinsicObfuscate,
6
+ NetworkingObfuscationMarker,
7
+ NetworkRaw,
8
+ NetworkUnreliable,
9
+ ObfuscateNames,
10
+ } from "../types";
11
+ import { EventNetworkingEvents } from "../handlers";
12
+ import { EventMiddleware } from "../middleware/types";
13
+ import { Modding } from "@flamework-experimental/core";
14
+
15
+ /**
16
+ * A sender declared `Networking.RawReliable` / `RawUnreliable`: its arguments travel as they are.
17
+ * Without the hidden marker below, no call site packs them and the peer runs no decoder.
18
+ */
19
+ export interface RawServerSender<I extends unknown[]> {
20
+ (player: Player | Player[], ...args: I): void;
21
+
22
+ /**
23
+ * Sends this request to the specified player(s).
24
+ * @param players The player(s) that will receive this event
25
+ */
26
+ fire(players: Player | Player[], ...args: I): void;
27
+
28
+ /**
29
+ * Sends this request to all players, excluding the specified player(s).
30
+ * @param players The player(s) that will not receive this event
31
+ */
32
+ except(players: Player | Player[], ...args: I): void;
33
+
34
+ /**
35
+ * Sends this request to all connected players.
36
+ */
37
+ broadcast(...args: I): void;
38
+ }
39
+
40
+ export interface ServerSender<I extends unknown[]> extends RawServerSender<I> {
41
+ /** @hidden Marks a sender for the transformer, which packs its arguments at each call site. */
42
+ readonly _flamework_send?: I;
43
+
44
+ /** @hidden Sends an argument list the transformer already packed; nothing when the list carries nothing. */
45
+ _fire(players: Player | Player[], payload?: buffer, blobs?: Array<defined>): void;
46
+
47
+ /** @hidden Sends an argument list the transformer already packed; nothing when the list carries nothing. */
48
+ _except(players: Player | Player[], payload?: buffer, blobs?: Array<defined>): void;
49
+
50
+ /** @hidden Sends an argument list the transformer already packed; nothing when the list carries nothing. */
51
+ _broadcast(payload?: buffer, blobs?: Array<defined>): void;
52
+ }
53
+
54
+ export interface RawServerReceiver<I extends unknown[]> {
55
+ /**
56
+ * Connect to this networking event.
57
+ * @param callback The callback that will be fired
58
+ */
59
+ connect(cb: (player: Player, ...args: I) => void): RBXScriptConnection;
60
+
61
+ /**
62
+ * Fires a server event using player as the sender.
63
+ */
64
+ predict(player: Player, ...args: I): void;
65
+ }
66
+
67
+ export interface ServerReceiver<I extends unknown[]> extends RawServerReceiver<I> {
68
+ /** @hidden Marks a receiver for the transformer. */
69
+ readonly _flamework_receive?: I;
70
+ }
71
+
72
+ export interface RawClientSender<I extends unknown[]> {
73
+ (...args: I): void;
74
+
75
+ /**
76
+ * Sends this request to the server.
77
+ */
78
+ fire(...args: I): void;
79
+ }
80
+
81
+ export interface ClientSender<I extends unknown[]> extends RawClientSender<I> {
82
+ /** @hidden Marks a sender for the transformer, which packs its arguments at each call site. */
83
+ readonly _flamework_send?: I;
84
+
85
+ /** @hidden Sends an argument list the transformer already packed; nothing when the list carries nothing. */
86
+ _fire(payload?: buffer, blobs?: Array<defined>): void;
87
+ }
88
+
89
+ export interface RawClientReceiver<I extends unknown[]> {
90
+ /**
91
+ * Connect to this networking event.
92
+ * @param callback The callback that will be fired
93
+ */
94
+ connect(cb: (...args: I) => void): RBXScriptConnection;
95
+
96
+ /**
97
+ * Fires a client event.
98
+ */
99
+ predict(...args: I): void;
100
+ }
101
+
102
+ export interface ClientReceiver<I extends unknown[]> extends RawClientReceiver<I> {
103
+ /** @hidden Marks a receiver for the transformer. */
104
+ readonly _flamework_receive?: I;
105
+ }
106
+
107
+ export type ServerHandler<E, R> = NetworkingObfuscationMarker & {
108
+ [k in keyof Events<E>]: E[k] extends NetworkRaw<unknown>
109
+ ? RawServerSender<FunctionParameters<E[k]>>
110
+ : ServerSender<FunctionParameters<E[k]>>;
111
+ } & {
112
+ [k in keyof Events<R>]: R[k] extends NetworkRaw<unknown>
113
+ ? RawServerReceiver<FunctionParameters<R[k]>>
114
+ : ServerReceiver<FunctionParameters<R[k]>>;
115
+ } & {
116
+ [k in keyof EventNamespaces<E>]: ServerHandler<E[k], k extends keyof R ? R[k] : {}>;
117
+ } & {
118
+ [k in keyof EventNamespaces<R>]: ServerHandler<k extends keyof E ? E[k] : {}, R[k]>;
119
+ };
120
+
121
+ export type ClientHandler<E, R> = NetworkingObfuscationMarker & {
122
+ [k in keyof Events<E>]: E[k] extends NetworkRaw<unknown>
123
+ ? RawClientSender<FunctionParameters<E[k]>>
124
+ : ClientSender<FunctionParameters<E[k]>>;
125
+ } & {
126
+ [k in keyof Events<R>]: R[k] extends NetworkRaw<unknown>
127
+ ? RawClientReceiver<FunctionParameters<R[k]>>
128
+ : ClientReceiver<FunctionParameters<R[k]>>;
129
+ } & {
130
+ [k in keyof EventNamespaces<E>]: ClientHandler<E[k], k extends keyof R ? R[k] : {}>;
131
+ } & {
132
+ [k in keyof EventNamespaces<R>]: ClientHandler<k extends keyof E ? E[k] : {}, R[k]>;
133
+ };
134
+
135
+ export interface EventCreateConfiguration<T> {
136
+ /**
137
+ * Disables input validation, allowing any value to pass.
138
+ * Defaults to `false`
139
+ */
140
+ disableIncomingGuards: boolean;
141
+
142
+ /**
143
+ * Emit a warning whenever a guard fails.
144
+ * Defaults to `RunService.IsStudio()`
145
+ */
146
+ warnOnInvalidGuards: boolean;
147
+
148
+ /**
149
+ * The middleware for each event.
150
+ */
151
+ middleware: EventMiddlewareList<T>;
152
+ }
153
+
154
+ export interface GlobalEvent<S, C> {
155
+ /**
156
+ * This is the server implementation of the network and does not exist on the client.
157
+ *
158
+ * @metadata macro {@link config intrinsic-const} {@link config intrinsic-middleware}
159
+ */
160
+ createServer(config: Partial<EventCreateConfiguration<S>>, meta?: NamespaceMetadata<S, C>): ServerHandler<C, S>;
161
+
162
+ /**
163
+ * This is the client implementation of the network and does not exist on the server.
164
+ *
165
+ * @metadata macro {@link config intrinsic-const} {@link config intrinsic-middleware}
166
+ */
167
+ createClient(config: Partial<EventCreateConfiguration<C>>, meta?: NamespaceMetadata<C, S>): ClientHandler<S, C>;
168
+
169
+ /**
170
+ * Registers a networking event handler.
171
+ * @param key The name of the event
172
+ * @param callback The handler you wish to attach
173
+ */
174
+ registerHandler<K extends keyof EventNetworkingEvents>(
175
+ key: K,
176
+ callback: EventNetworkingEvents[K],
177
+ ): RBXScriptConnection;
178
+ }
179
+
180
+ export type EventNamespaces<T> = ExcludeMembers<T, Callback>;
181
+ export type Events<T> = ExtractMembers<T, Callback>;
182
+
183
+ export type NamespaceMetadata<R, S> = Modding.Emit<{
184
+ incomingIds: ObfuscateNames<keyof Events<R>>;
185
+ incoming: IntrinsicObfuscate<{ [k in keyof Events<R>]: IntrinsicTupleGuards<Parameters<Events<R>[k]>> }>;
186
+ incomingUnreliable: IntrinsicObfuscate<{
187
+ [k in keyof Events<R>]: R[k] extends NetworkUnreliable<unknown> ? true : undefined;
188
+ }>;
189
+
190
+ outgoingIds: ObfuscateNames<keyof Events<S>>;
191
+ outgoingUnreliable: IntrinsicObfuscate<{
192
+ [k in keyof Events<S>]: S[k] extends NetworkUnreliable<unknown> ? true : undefined;
193
+ }>;
194
+
195
+ /**
196
+ * Decoders for each incoming event's argument list, present only with `networking.serialization`
197
+ * on, and absent for raw events and for lists that carry nothing. Outgoing lists are packed
198
+ * inline where they are fired; nothing here can encode.
199
+ */
200
+ incomingSerializers: IntrinsicObfuscate<{
201
+ [k in keyof Events<R>]: R[k] extends NetworkRaw<unknown>
202
+ ? undefined
203
+ : IntrinsicNetworkDecoder<Parameters<Events<R>[k]>>;
204
+ }>;
205
+
206
+ namespaceIds: ObfuscateNames<keyof EventNamespaces<R> | keyof EventNamespaces<S>>;
207
+ namespaces: IntrinsicObfuscate<
208
+ {
209
+ [k in keyof EventNamespaces<R>]: NamespaceMetadata<R[k], k extends keyof S ? S[k] : {}>;
210
+ } & {
211
+ [k in keyof EventNamespaces<S>]: NamespaceMetadata<k extends keyof R ? R[k] : {}, S[k]>;
212
+ }
213
+ >;
214
+ }>;
215
+
216
+ export type EventMiddlewareList<T> = {
217
+ readonly [k in keyof Events<T>]?: T[k] extends (...args: infer I) => void ? [...EventMiddleware<I>[]] : never;
218
+ } & {
219
+ readonly [k in keyof EventNamespaces<T>]?: EventMiddlewareList<T[k]>;
220
+ };
@@ -0,0 +1,52 @@
1
+ import { Serialization } from "@flamework-experimental/core";
2
+ import { NetworkInfo } from "../types";
3
+ import { NetworkingFunctionError } from "./errors";
4
+ import { MiddlewareFactory } from "../middleware/types";
5
+ export interface CreateFunctionReceiverOptions {
6
+ /**
7
+ * The namespace this event should be created in.
8
+ */
9
+ namespace: string;
10
+ /**
11
+ * The name of the remote instance, not necessarily unique and used for debugging purposes.
12
+ */
13
+ debugName: string;
14
+ /**
15
+ * The remote's ID which must be unique.
16
+ */
17
+ id: string;
18
+ /**
19
+ * Information about the network, which includes some of the above.
20
+ *
21
+ * Passed to the middleware.
22
+ */
23
+ networkInfo: NetworkInfo;
24
+ /**
25
+ * This function will be called when we receive a response, and can be used to resolve or reject values.
26
+ */
27
+ incomingMiddleware?: MiddlewareFactory<any[], any>[];
28
+ /**
29
+ * Unpacks the request's argument list. Absent when the project does not enable serialization.
30
+ */
31
+ argsDecoder?: Serialization.Decoder;
32
+ /**
33
+ * Unpacks the results a packed callback returns, so that `predict` resolves with the value itself.
34
+ * Absent when the project does not enable serialization.
35
+ */
36
+ resultDecoder?: Serialization.Decoder;
37
+ /**
38
+ * Called when a request cannot be decoded; the caller receives `BadRequest`.
39
+ */
40
+ onMalformed?: (player: Player | undefined, message: string) => void;
41
+ }
42
+ export interface RequestInfo {
43
+ nextId: number;
44
+ requests: Map<number, (value: unknown, rejection?: NetworkingFunctionError) => void>;
45
+ }
46
+ export interface FunctionReceiverInterface {
47
+ /** `packed`: the callback returns successful results as `[payload, blobs?]`, packed by the transformer. */
48
+ setServerCallback(callback: (player: Player, ...args: unknown[]) => unknown, packed?: boolean): void;
49
+ setClientCallback(callback: (...args: unknown[]) => unknown, packed?: boolean): void;
50
+ invoke(player: Player | undefined, ...args: unknown[]): Promise<unknown>;
51
+ }
52
+ export declare function createFunctionReceiver(options: CreateFunctionReceiverOptions): FunctionReceiverInterface;
@@ -0,0 +1,118 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local RunService = TS.import(script, TS.getModule(script, "@rbxts", "services")).RunService
4
+ local _createEvent = TS.import(script, script.Parent.Parent, "event", "createEvent")
5
+ local createEvent = _createEvent.createEvent
6
+ local decodeArguments = _createEvent.decodeArguments
7
+ local NetworkingFunctionError = TS.import(script, script.Parent, "errors").NetworkingFunctionError
8
+ local createMiddlewareProcessor = TS.import(script, script.Parent.Parent, "middleware", "createMiddlewareProcessor").createMiddlewareProcessor
9
+ local _skip = TS.import(script, script.Parent.Parent, "middleware", "skip")
10
+ local Skip = _skip.Skip
11
+ local SkipBadRequest = _skip.SkipBadRequest
12
+ local getProcessResult
13
+ local function createFunctionReceiver(options)
14
+ local event = createEvent({
15
+ namespace = options.namespace,
16
+ debugName = options.debugName,
17
+ id = options.id,
18
+ networkInfo = options.networkInfo,
19
+ })
20
+ local callback
21
+ local packedResults = false
22
+ local setCallback = function(newCallback, packed)
23
+ packedResults = packed
24
+ callback = createMiddlewareProcessor(options.incomingMiddleware, options.networkInfo, function(player, ...)
25
+ local args = { ... }
26
+ if RunService:IsServer() then
27
+ return newCallback(player, unpack(args))
28
+ else
29
+ return newCallback(unpack(args))
30
+ end
31
+ end)
32
+ end
33
+ --[[
34
+ *
35
+ * A packed callback's successful value is `[payload, blobs?]`, or nothing at all when the result
36
+ * type carries nothing (`void`); errors always go back as they are.
37
+
38
+ ]]
39
+ local respond = function(player, id, processResult, value)
40
+ if processResult == true and packedResults and value ~= nil then
41
+ local _binding = value
42
+ local payload = _binding[1]
43
+ local blobs = _binding[2]
44
+ event:fireEither(player, id, processResult, payload, blobs)
45
+ else
46
+ event:fireEither(player, id, processResult, value)
47
+ end
48
+ end
49
+ local processRequest = function(player, id, ...)
50
+ local args = { ... }
51
+ if not callback then
52
+ return event:fireEither(player, id, NetworkingFunctionError.Unprocessed)
53
+ end
54
+ local decoded = decodeArguments(options.argsDecoder, player, args, options.onMalformed)
55
+ if not decoded then
56
+ return event:fireEither(player, id, NetworkingFunctionError.BadRequest)
57
+ end
58
+ callback(player, unpack(decoded)):andThen(function(value)
59
+ return respond(player, id, getProcessResult(value), value)
60
+ end):catch(function(reason)
61
+ warn(`Failed to process request to '{options.debugName}'`)
62
+ warn(reason)
63
+ event:fireEither(player, id, false)
64
+ end)
65
+ end
66
+ if RunService:IsServer() then
67
+ event:connectServer(function(player, id, ...)
68
+ local args = { ... }
69
+ return processRequest(player, id, unpack(args))
70
+ end)
71
+ else
72
+ event:connectClient(function(id, ...)
73
+ local args = { ... }
74
+ return processRequest(nil, id, unpack(args))
75
+ end)
76
+ end
77
+ return {
78
+ setServerCallback = function(self, callback, packed)
79
+ if packed == nil then
80
+ packed = false
81
+ end
82
+ setCallback(callback, packed)
83
+ end,
84
+ setClientCallback = function(self, callback, packed)
85
+ if packed == nil then
86
+ packed = false
87
+ end
88
+ setCallback(callback, packed)
89
+ end,
90
+ invoke = function(self, player, ...)
91
+ local args = { ... }
92
+ if not callback then
93
+ return TS.Promise.reject(NetworkingFunctionError.Unprocessed)
94
+ end
95
+ return callback(player, unpack(args)):andThen(function(value)
96
+ local processResult = getProcessResult(value)
97
+ if processResult ~= true then
98
+ return TS.Promise.reject(processResult)
99
+ end
100
+ -- A packed callback answered with bytes; a local caller wants the value.
101
+ local decoder = options.resultDecoder
102
+ if not packedResults or not decoder then
103
+ return value
104
+ end
105
+ local _binding = value
106
+ local payload = _binding[1]
107
+ local blobs = _binding[2]
108
+ return decoder(payload, blobs or {})[1]
109
+ end)
110
+ end,
111
+ }
112
+ end
113
+ function getProcessResult(value)
114
+ return if value == Skip then NetworkingFunctionError.Cancelled elseif value == SkipBadRequest then NetworkingFunctionError.BadRequest else true
115
+ end
116
+ return {
117
+ createFunctionReceiver = createFunctionReceiver,
118
+ }
@@ -0,0 +1,45 @@
1
+ import { Serialization } from "@flamework-experimental/core";
2
+ import { NetworkInfo } from "../types";
3
+ import { NetworkingFunctionError } from "./errors";
4
+ export interface CreateFunctionSenderOptions {
5
+ /**
6
+ * The namespace this event should be created in.
7
+ */
8
+ namespace: string;
9
+ /**
10
+ * The name of the remote instance, not necessarily unique and used for debugging purposes.
11
+ */
12
+ debugName: string;
13
+ /**
14
+ * The remote's ID which must be unique.
15
+ */
16
+ id: string;
17
+ /**
18
+ * Information about the network, which includes some of the above.
19
+ *
20
+ * Passed to the middleware.
21
+ */
22
+ networkInfo: NetworkInfo;
23
+ /**
24
+ * This function will be called when we receive a response, and can be used to resolve or reject values.
25
+ */
26
+ responseMiddleware?: (player: Player | undefined, value: unknown, resolve: (value: unknown) => void, reject: (value: unknown) => void) => void;
27
+ /**
28
+ * Unpacks a successful response's value, carried as a one-element list. Absent when the project
29
+ * does not enable serialization. Requests reach `invoke*` already packed by the transformer.
30
+ */
31
+ resultDecoder?: Serialization.Decoder;
32
+ /**
33
+ * Called when a response cannot be decoded; the request is rejected with `InvalidResult`.
34
+ */
35
+ onMalformed?: (player: Player | undefined, message: string) => void;
36
+ }
37
+ export interface RequestInfo {
38
+ nextId: number;
39
+ requests: Map<number, (value: unknown, rejection?: NetworkingFunctionError) => void>;
40
+ }
41
+ export interface FunctionSenderInterface {
42
+ invokeServer(...args: unknown[]): Promise<unknown>;
43
+ invokeClient(player: Player, ...args: unknown[]): Promise<unknown>;
44
+ }
45
+ export declare function createFunctionSender(options: CreateFunctionSenderOptions): FunctionSenderInterface;
@@ -0,0 +1,135 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local _services = TS.import(script, TS.getModule(script, "@rbxts", "services"))
4
+ local Players = _services.Players
5
+ local RunService = _services.RunService
6
+ local _createEvent = TS.import(script, script.Parent.Parent, "event", "createEvent")
7
+ local createEvent = _createEvent.createEvent
8
+ local decodeArguments = _createEvent.decodeArguments
9
+ local _errors = TS.import(script, script.Parent, "errors")
10
+ local NetworkingFunctionError = _errors.NetworkingFunctionError
11
+ local getFunctionError = _errors.getFunctionError
12
+ local t = TS.import(script, TS.getModule(script, "@rbxts", "t").lib.ts).t
13
+ local createRequestInfo
14
+ local function createFunctionSender(options)
15
+ local event = createEvent({
16
+ namespace = options.namespace,
17
+ debugName = options.debugName,
18
+ id = options.id,
19
+ networkInfo = options.networkInfo,
20
+ })
21
+ local processResponse = function(player, requestInfo, id, processResult, ...)
22
+ local response = { ... }
23
+ if not t.number(id) then
24
+ return nil
25
+ end
26
+ local _requests = requestInfo.requests
27
+ local _id = id
28
+ local request = _requests[_id]
29
+ local _requests_1 = requestInfo.requests
30
+ local _id_1 = id
31
+ _requests_1[_id_1] = nil
32
+ if not request then
33
+ return nil
34
+ end
35
+ local rejection = getFunctionError(processResult)
36
+ if rejection ~= nil or not options.resultDecoder then
37
+ request(response[1], rejection)
38
+ return nil
39
+ end
40
+ -- A successful response carries the packed value: `(buffer, blobs?)`.
41
+ local decoded = decodeArguments(options.resultDecoder, player, response, options.onMalformed)
42
+ if not decoded then
43
+ request(nil, NetworkingFunctionError.InvalidResult)
44
+ return nil
45
+ end
46
+ request(decoded[1], nil)
47
+ end
48
+ -- We don't need to defer here because we only accept responses to our explicit invocations.
49
+ local requestInfoServer = {}
50
+ local requestInfoClient = createRequestInfo()
51
+ if RunService:IsServer() then
52
+ event:connectServer(function(player, id, processResult, ...)
53
+ local response = { ... }
54
+ local _player = player
55
+ local requestInfo = requestInfoServer[_player]
56
+ if not requestInfo then
57
+ return nil
58
+ end
59
+ processResponse(player, requestInfo, id, processResult, unpack(response))
60
+ end)
61
+ Players.PlayerRemoving:Connect(function(player)
62
+ local _player = player
63
+ local requestInfo = requestInfoServer[_player]
64
+ local _player_1 = player
65
+ requestInfoServer[_player_1] = nil
66
+ if requestInfo then
67
+ -- Cancel all existing requests from this player.
68
+ for _, request in requestInfo.requests do
69
+ request(nil, NetworkingFunctionError.Cancelled)
70
+ end
71
+ end
72
+ end)
73
+ else
74
+ event:connectClient(function(id, processResult, ...)
75
+ local response = { ... }
76
+ processResponse(nil, requestInfoClient, id, processResult, unpack(response))
77
+ end)
78
+ end
79
+ local createInvocation = function(player, id, requestInfo)
80
+ return TS.Promise.new(function(resolve, reject, onCancel)
81
+ local _requests = requestInfo.requests
82
+ local _id = id
83
+ _requests[_id] = function(value, rejection)
84
+ if rejection then
85
+ return reject(rejection)
86
+ end
87
+ if options.responseMiddleware then
88
+ options.responseMiddleware(player, value, resolve, reject)
89
+ else
90
+ resolve(value)
91
+ end
92
+ end
93
+ onCancel(function()
94
+ local _requests_1 = requestInfo.requests
95
+ local _id_1 = id
96
+ _requests_1[_id_1] = nil
97
+ end)
98
+ end)
99
+ end
100
+ return {
101
+ invokeServer = function(self, ...)
102
+ local args = { ... }
103
+ local _original = requestInfoClient.nextId
104
+ requestInfoClient.nextId += 1
105
+ local id = _original
106
+ event:fireServer(id, unpack(args))
107
+ return createInvocation(nil, id, requestInfoClient)
108
+ end,
109
+ invokeClient = function(self, player, ...)
110
+ local args = { ... }
111
+ local _player = player
112
+ local requestInfo = requestInfoServer[_player]
113
+ if not requestInfo then
114
+ local _exp = player
115
+ requestInfo = createRequestInfo()
116
+ local _requestInfo = requestInfo
117
+ requestInfoServer[_exp] = _requestInfo
118
+ end
119
+ local _original = requestInfoClient.nextId
120
+ requestInfoClient.nextId += 1
121
+ local id = _original
122
+ event:fireClient(player, id, unpack(args))
123
+ return createInvocation(player, id, requestInfo)
124
+ end,
125
+ }
126
+ end
127
+ function createRequestInfo()
128
+ return {
129
+ nextId = 0,
130
+ requests = {},
131
+ }
132
+ end
133
+ return {
134
+ createFunctionSender = createFunctionSender,
135
+ }
@@ -0,0 +1,10 @@
1
+ import { t as t } from "@rbxts/t";
2
+ export declare const isNetworkingFunctionError: t.check<NetworkingFunctionError>;
3
+ export declare enum NetworkingFunctionError {
4
+ Timeout = "Timeout",
5
+ Cancelled = "Cancelled",
6
+ BadRequest = "BadRequest",
7
+ Unprocessed = "Unprocessed",
8
+ InvalidResult = "InvalidResult"
9
+ }
10
+ export declare function getFunctionError(value: unknown): NetworkingFunctionError | undefined;
@@ -0,0 +1,25 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local t = TS.import(script, TS.getModule(script, "@rbxts", "t").lib.ts).t
4
+ local Flamework = TS.import(script, TS.getModule(script, "@flamework-experimental", "core").out).Flamework
5
+ local isNetworkingFunctionError = Flamework.createGuard(t.literalList({ "Timeout", "Cancelled", "BadRequest", "Unprocessed", "InvalidResult" }))
6
+ local NetworkingFunctionError = {
7
+ Timeout = "Timeout",
8
+ Cancelled = "Cancelled",
9
+ BadRequest = "BadRequest",
10
+ Unprocessed = "Unprocessed",
11
+ InvalidResult = "InvalidResult",
12
+ }
13
+ local function getFunctionError(value)
14
+ local _value = value
15
+ if type(_value) == "boolean" then
16
+ return if value == false then NetworkingFunctionError.Unprocessed else nil
17
+ elseif isNetworkingFunctionError(value) then
18
+ return value
19
+ end
20
+ end
21
+ return {
22
+ getFunctionError = getFunctionError,
23
+ isNetworkingFunctionError = isNetworkingFunctionError,
24
+ NetworkingFunctionError = NetworkingFunctionError,
25
+ }
@@ -0,0 +1,15 @@
1
+ import { FunctionReceiverInterface } from "../function/createFunctionReceiver";
2
+ import { FunctionSenderInterface } from "../function/createFunctionSender";
3
+ import { FunctionCreateConfiguration } from "./types";
4
+ export declare function createClientMethod(config: FunctionCreateConfiguration<unknown>, receiver?: FunctionReceiverInterface, sender?: FunctionSenderInterface): {
5
+ readonly _flamework_send?: unknown[] | undefined;
6
+ _invoke: (payload?: buffer, blobs?: Array<defined>) => Promise<unknown>;
7
+ _invokeWithTimeout: (timeout: number, payload?: buffer, blobs?: Array<defined>) => Promise<unknown>;
8
+ invoke: (...args: unknown[]) => Promise<unknown>;
9
+ invokeWithTimeout: (timeout: number, ...args: unknown[]) => Promise<unknown>;
10
+ readonly _flamework_receive?: unknown[] | undefined;
11
+ readonly _flamework_fn?: unknown;
12
+ _setCallback: (callback: (...args: never[]) => unknown) => void;
13
+ setCallback: (callback: (...args: unknown[]) => unknown | Promise<unknown>) => void;
14
+ predict: (...args: unknown[]) => Promise<unknown>;
15
+ };
@@ -0,0 +1,52 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local NetworkingFunctionError = TS.import(script, script.Parent.Parent, "function", "errors").NetworkingFunctionError
4
+ local timeoutPromise = TS.import(script, script.Parent.Parent, "util", "timeoutPromise").timeoutPromise
5
+ local function createClientMethod(config, receiver, sender)
6
+ local method = {
7
+ invoke = function(self, ...)
8
+ local args = { ... }
9
+ return self:invokeWithTimeout(config.defaultTimeout, unpack(args))
10
+ end,
11
+ invokeWithTimeout = function(self, timeout, ...)
12
+ local args = { ... }
13
+ local _sender = sender
14
+ assert(_sender, "This is not a sender remote.")
15
+ return TS.Promise.race({ timeoutPromise(timeout, NetworkingFunctionError.Timeout), sender:invokeServer(unpack(args)) })
16
+ end,
17
+ _invoke = function(self, ...)
18
+ local packed = { ... }
19
+ return self:invokeWithTimeout(config.defaultTimeout, unpack(packed))
20
+ end,
21
+ _invokeWithTimeout = function(self, timeout, ...)
22
+ local packed = { ... }
23
+ return self:invokeWithTimeout(timeout, unpack(packed))
24
+ end,
25
+ setCallback = function(self, callback)
26
+ local _receiver = receiver
27
+ assert(_receiver, "This is not a receiver remote.")
28
+ receiver:setClientCallback(callback)
29
+ end,
30
+ _setCallback = function(self, callback)
31
+ local _receiver = receiver
32
+ assert(_receiver, "This is not a receiver remote.")
33
+ receiver:setClientCallback(callback, true)
34
+ end,
35
+ predict = function(self, ...)
36
+ local args = { ... }
37
+ local _receiver = receiver
38
+ assert(_receiver, "This is not a receiver remote.")
39
+ return receiver:invoke(nil, unpack(args))
40
+ end,
41
+ }
42
+ setmetatable(method, {
43
+ __call = function(method, ...)
44
+ local args = { ... }
45
+ return method:invoke(unpack(args))
46
+ end,
47
+ })
48
+ return method
49
+ end
50
+ return {
51
+ createClientMethod = createClientMethod,
52
+ }
@@ -0,0 +1,7 @@
1
+ import { FunctionNetworkingEvents } from "../handlers";
2
+ import { ClientHandler, FunctionCreateConfiguration, NamespaceMetadata, ServerHandler } from "./types";
3
+ import { SignalContainer } from "../util/createSignalContainer";
4
+ import { FunctionReceiverInterface } from "../function/createFunctionReceiver";
5
+ import { FunctionSenderInterface } from "../function/createFunctionSender";
6
+ export type MethodCreator = (config: FunctionCreateConfiguration<unknown>, receiver?: FunctionReceiverInterface, sender?: FunctionSenderInterface) => unknown;
7
+ export declare function createGenericHandler<T extends ClientHandler<S, R> | ServerHandler<S, R>, S, R>(globalName: string, namespaceName: string | undefined, receiverPrefix: string, senderPrefix: string, metadata: NamespaceMetadata<R, S>, config: FunctionCreateConfiguration<R>, signals: SignalContainer<FunctionNetworkingEvents>, createMethod: MethodCreator): T;