@trioforge/crucible 0.0.0-stage → 0.2.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 (183) hide show
  1. package/LICENSE +21 -0
  2. package/client/package.json +4 -0
  3. package/emit/package.json +4 -0
  4. package/out/all.d.ts +7 -0
  5. package/out/all.luau +2 -0
  6. package/out/attribute.d.ts +7 -0
  7. package/out/attribute.luau +7 -0
  8. package/out/client/index.d.ts +10 -0
  9. package/out/client/init.luau +55 -0
  10. package/out/configs.d.ts +37 -0
  11. package/out/configs.luau +46 -0
  12. package/out/crucible-behaviour.d.ts +16 -0
  13. package/out/crucible-behaviour.luau +78 -0
  14. package/out/crucible-object.d.ts +10 -0
  15. package/out/crucible-object.luau +69 -0
  16. package/out/data.d.ts +224 -0
  17. package/out/data.luau +97 -0
  18. package/out/emit/configs.d.ts +4 -0
  19. package/out/emit/configs.luau +22 -0
  20. package/out/emit/data.d.ts +6 -0
  21. package/out/emit/data.luau +19 -0
  22. package/out/emit/index.d.ts +45 -0
  23. package/out/emit/init.luau +101 -0
  24. package/out/emit/network.d.ts +6 -0
  25. package/out/emit/network.luau +36 -0
  26. package/out/emit/replicated.d.ts +4 -0
  27. package/out/emit/replicated.luau +13 -0
  28. package/out/index.d.ts +20 -0
  29. package/out/init.luau +34 -0
  30. package/out/inject.d.ts +1 -0
  31. package/out/inject.luau +7 -0
  32. package/out/internal/binding.d.ts +1 -0
  33. package/out/internal/binding.luau +615 -0
  34. package/out/internal/boot.d.ts +1 -0
  35. package/out/internal/boot.luau +562 -0
  36. package/out/internal/configs/limits.d.ts +10 -0
  37. package/out/internal/configs/limits.luau +25 -0
  38. package/out/internal/configs/port.d.ts +29 -0
  39. package/out/internal/configs/port.luau +99 -0
  40. package/out/internal/configs/runtime.d.ts +21 -0
  41. package/out/internal/configs/runtime.luau +981 -0
  42. package/out/internal/construction-claim.d.ts +1 -0
  43. package/out/internal/construction-claim.luau +26 -0
  44. package/out/internal/data/admission.d.ts +1 -0
  45. package/out/internal/data/admission.luau +673 -0
  46. package/out/internal/data/declarations.d.ts +1 -0
  47. package/out/internal/data/declarations.luau +384 -0
  48. package/out/internal/data/envelope.d.ts +1 -0
  49. package/out/internal/data/envelope.luau +318 -0
  50. package/out/internal/data/handles.d.ts +1 -0
  51. package/out/internal/data/handles.luau +255 -0
  52. package/out/internal/data/inbox-transforms.d.ts +1 -0
  53. package/out/internal/data/inbox-transforms.luau +458 -0
  54. package/out/internal/data/inbox.d.ts +1 -0
  55. package/out/internal/data/inbox.luau +437 -0
  56. package/out/internal/data/lease.d.ts +1 -0
  57. package/out/internal/data/lease.luau +304 -0
  58. package/out/internal/data/limits.d.ts +1 -0
  59. package/out/internal/data/limits.luau +234 -0
  60. package/out/internal/data/messages.d.ts +1 -0
  61. package/out/internal/data/messages.luau +69 -0
  62. package/out/internal/data/operation-id.d.ts +1 -0
  63. package/out/internal/data/operation-id.luau +61 -0
  64. package/out/internal/data/paths.d.ts +2 -0
  65. package/out/internal/data/paths.luau +323 -0
  66. package/out/internal/data/port.d.ts +1 -0
  67. package/out/internal/data/port.luau +290 -0
  68. package/out/internal/data/profiles.d.ts +1 -0
  69. package/out/internal/data/profiles.luau +862 -0
  70. package/out/internal/data/receipts.d.ts +1 -0
  71. package/out/internal/data/receipts.luau +190 -0
  72. package/out/internal/data/record-bindings.d.ts +1 -0
  73. package/out/internal/data/record-bindings.luau +92 -0
  74. package/out/internal/data/record-declarations.d.ts +1 -0
  75. package/out/internal/data/record-declarations.luau +140 -0
  76. package/out/internal/data/records.d.ts +1 -0
  77. package/out/internal/data/records.luau +400 -0
  78. package/out/internal/data/runtime.d.ts +1 -0
  79. package/out/internal/data/runtime.luau +918 -0
  80. package/out/internal/data/scheduler.d.ts +1 -0
  81. package/out/internal/data/scheduler.luau +507 -0
  82. package/out/internal/data/session.d.ts +1 -0
  83. package/out/internal/data/session.luau +234 -0
  84. package/out/internal/data/shutdown.d.ts +1 -0
  85. package/out/internal/data/shutdown.luau +91 -0
  86. package/out/internal/data/waiters.d.ts +1 -0
  87. package/out/internal/data/waiters.luau +65 -0
  88. package/out/internal/dense-list.d.ts +1 -0
  89. package/out/internal/dense-list.luau +155 -0
  90. package/out/internal/diagnostics.d.ts +1 -0
  91. package/out/internal/diagnostics.luau +29 -0
  92. package/out/internal/hooks.d.ts +1 -0
  93. package/out/internal/hooks.luau +53 -0
  94. package/out/internal/implementers.d.ts +1 -0
  95. package/out/internal/implementers.luau +119 -0
  96. package/out/internal/lifecycle.d.ts +1 -0
  97. package/out/internal/lifecycle.luau +912 -0
  98. package/out/internal/log-output.d.ts +1 -0
  99. package/out/internal/log-output.luau +106 -0
  100. package/out/internal/network/catalog.d.ts +26 -0
  101. package/out/internal/network/catalog.luau +182 -0
  102. package/out/internal/network/claims.d.ts +1 -0
  103. package/out/internal/network/claims.luau +154 -0
  104. package/out/internal/network/client-session.d.ts +1 -0
  105. package/out/internal/network/client-session.luau +403 -0
  106. package/out/internal/network/codec.d.ts +63 -0
  107. package/out/internal/network/codec.luau +1183 -0
  108. package/out/internal/network/envelope.d.ts +1 -0
  109. package/out/internal/network/envelope.luau +247 -0
  110. package/out/internal/network/limits.d.ts +26 -0
  111. package/out/internal/network/limits.luau +55 -0
  112. package/out/internal/network/port.d.ts +1 -0
  113. package/out/internal/network/port.luau +19 -0
  114. package/out/internal/network/roblox-network-port.d.ts +1 -0
  115. package/out/internal/network/roblox-network-port.luau +105 -0
  116. package/out/internal/network/schema.d.ts +72 -0
  117. package/out/internal/network/schema.luau +386 -0
  118. package/out/internal/network/server-session.d.ts +1 -0
  119. package/out/internal/network/server-session.luau +393 -0
  120. package/out/internal/network/session.d.ts +1 -0
  121. package/out/internal/network/session.luau +266 -0
  122. package/out/internal/port.d.ts +1 -0
  123. package/out/internal/port.luau +12 -0
  124. package/out/internal/reactive/context.d.ts +1 -0
  125. package/out/internal/reactive/context.luau +149 -0
  126. package/out/internal/reactive/flush.d.ts +1 -0
  127. package/out/internal/reactive/flush.luau +355 -0
  128. package/out/internal/reactive/graph.d.ts +1 -0
  129. package/out/internal/reactive/graph.luau +626 -0
  130. package/out/internal/reactive/limits.d.ts +1 -0
  131. package/out/internal/reactive/limits.luau +54 -0
  132. package/out/internal/reactive/ownership.d.ts +1 -0
  133. package/out/internal/reactive/ownership.luau +626 -0
  134. package/out/internal/registry.d.ts +1 -0
  135. package/out/internal/registry.luau +455 -0
  136. package/out/internal/roblox-port.d.ts +1 -0
  137. package/out/internal/roblox-port.luau +117 -0
  138. package/out/internal/runner.d.ts +1 -0
  139. package/out/internal/runner.luau +86 -0
  140. package/out/internal/scheduler.d.ts +1 -0
  141. package/out/internal/scheduler.luau +207 -0
  142. package/out/internal/state.d.ts +1 -0
  143. package/out/internal/state.luau +41 -0
  144. package/out/internal/sync/client-sync.d.ts +1 -0
  145. package/out/internal/sync/client-sync.luau +157 -0
  146. package/out/internal/sync/declarations.d.ts +1 -0
  147. package/out/internal/sync/declarations.luau +276 -0
  148. package/out/internal/sync/frame.d.ts +1 -0
  149. package/out/internal/sync/frame.luau +91 -0
  150. package/out/internal/sync/server-sync.d.ts +1 -0
  151. package/out/internal/sync/server-sync.luau +502 -0
  152. package/out/internal/sync/values.d.ts +1 -0
  153. package/out/internal/sync/values.luau +930 -0
  154. package/out/log-level.d.ts +7 -0
  155. package/out/log-level.luau +21 -0
  156. package/out/logging.d.ts +34 -0
  157. package/out/logging.luau +233 -0
  158. package/out/network.d.ts +66 -0
  159. package/out/network.luau +24 -0
  160. package/out/reactive.d.ts +76 -0
  161. package/out/reactive.luau +136 -0
  162. package/out/replicated.d.ts +38 -0
  163. package/out/replicated.luau +45 -0
  164. package/out/server/data.d.ts +54 -0
  165. package/out/server/data.luau +44 -0
  166. package/out/server/index.d.ts +18 -0
  167. package/out/server/init.luau +62 -0
  168. package/out/server/publish.d.ts +20 -0
  169. package/out/server/publish.luau +24 -0
  170. package/out/subsystem.d.ts +4 -0
  171. package/out/subsystem.luau +30 -0
  172. package/out/vide/index.d.ts +7 -0
  173. package/out/vide/init.luau +50 -0
  174. package/package.json +52 -5
  175. package/server/package.json +4 -0
  176. package/transformer/data.cjs +72 -0
  177. package/transformer/declarations.cjs +153 -0
  178. package/transformer/diagnostics.cjs +19 -0
  179. package/transformer/index.js +741 -0
  180. package/transformer/network.cjs +961 -0
  181. package/transformer/type-id.cjs +80 -0
  182. package/vide/package.json +4 -0
  183. package/README.md +0 -3
@@ -0,0 +1,403 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local runtimeDiagnostic = TS.import(script, script.Parent.Parent, "diagnostics").runtimeDiagnostic
4
+ local _catalog = TS.import(script, script.Parent, "catalog")
5
+ local adopt = _catalog.adopt
6
+ local catalogSize = _catalog.catalogSize
7
+ local definitionAt = _catalog.definitionAt
8
+ local definitionOf = _catalog.definitionOf
9
+ local discardIndices = _catalog.discardIndices
10
+ local unpublished = _catalog.unpublished
11
+ local _claims = TS.import(script, script.Parent, "claims")
12
+ local closeClaims = _claims.closeClaims
13
+ local freezeClaims = _claims.freezeClaims
14
+ local openClaims = _claims.openClaims
15
+ local receiverOf = _claims.receiverOf
16
+ local _envelope = TS.import(script, script.Parent, "envelope")
17
+ local argumentCount = _envelope.argumentCount
18
+ local controlPacket = _envelope.controlPacket
19
+ local decodeBody = _envelope.decodeBody
20
+ local encodeBody = _envelope.encodeBody
21
+ local failureReason = _envelope.failureReason
22
+ local frame = _envelope.frame
23
+ local missingInstance = _envelope.missingInstance
24
+ local openBody = _envelope.openBody
25
+ local readHeader = _envelope.readHeader
26
+ local L = TS.import(script, script.Parent, "limits")
27
+ local _session = TS.import(script, script.Parent, "session")
28
+ local newPeer = _session.newPeer
29
+ local Session = _session.Session
30
+ local FAIL_NAMES = { "overflow", "overloaded", "closing", "malformed" }
31
+ local ERROR_REASONS = { "unavailable", "handler-error", "overloaded", "invalid" }
32
+ local function failed(reason)
33
+ return table.freeze({
34
+ ok = false,
35
+ reason = reason,
36
+ })
37
+ end
38
+ --* @internal
39
+ local toServer
40
+ local ClientSession
41
+ do
42
+ local super = Session
43
+ ClientSession = setmetatable({}, {
44
+ __tostring = function()
45
+ return "ClientSession"
46
+ end,
47
+ __index = super,
48
+ })
49
+ ClientSession.__index = ClientSession
50
+ function ClientSession.new(...)
51
+ local self = setmetatable({}, ClientSession)
52
+ return self:constructor(...) or self
53
+ end
54
+ function ClientSession:constructor(...)
55
+ super.constructor(self, ...)
56
+ self.peer = newPeer()
57
+ self.nextNonce = 1
58
+ self.pending = {}
59
+ self.fired = false
60
+ self.unpublishedReported = {}
61
+ self.undeclared = {}
62
+ self.unmatched = {}
63
+ self.undecoded = {}
64
+ self.missingPlayer = {}
65
+ end
66
+ function ClientSession:open()
67
+ self.stage = 1
68
+ openClaims({
69
+ side = "client",
70
+ retired = function() end,
71
+ })
72
+ local where = `ReplicatedStorage.{L.REMOTE_NAME}`
73
+ local found = self.port.discover(L.CLIENT_DISCOVERY_TIMEOUT_SECONDS, function(...)
74
+ local args = { ... }
75
+ return self:receive(argumentCount(args), args[1], args[2])
76
+ end)
77
+ if found == nil then
78
+ error(`Crucible found no {where} within {L.CLIENT_DISCOVERY_TIMEOUT_SECONDS} seconds`, 0)
79
+ end
80
+ if found.className ~= "RemoteEvent" then
81
+ error(`Crucible found {where} as a {found.className}`, 0)
82
+ end
83
+ if found.protocol ~= L.PROTOCOL_VERSION then
84
+ error(`Crucible {where} has Protocol {tostring(found.protocol)}; this client needs {L.PROTOCOL_VERSION}`, 0)
85
+ end
86
+ local adopted, err = pcall(adopt, found.catalog)
87
+ if not adopted then
88
+ error(`Crucible {where} has an invalid Catalog: {tostring(err)}`, 0)
89
+ end
90
+ end
91
+ function ClientSession:loaded()
92
+ self.stage = 2
93
+ end
94
+ function ClientSession:commit()
95
+ freezeClaims()
96
+ for _, definition in unpublished() do
97
+ if receiverOf(definition) ~= nil then
98
+ self:unpublished(definition)
99
+ end
100
+ end
101
+ if self.peer.state == 0 then
102
+ self:fire(self.peer, controlPacket(4, {}))
103
+ self.fired = true
104
+ self.peer.state = 1
105
+ self:flush(self.peer)
106
+ end
107
+ self.stage = 3
108
+ end
109
+ function ClientSession:close()
110
+ if self.stage == 4 then
111
+ return nil
112
+ end
113
+ local committed = self.stage == 3
114
+ self.stage = 4
115
+ if self.fired and self.peer.state ~= 2 then
116
+ pcall(function()
117
+ return self:fire(self.peer, controlPacket(5, {}, 2))
118
+ end)
119
+ end
120
+ pcall(function()
121
+ return self["end"](self, self.peer)
122
+ end)
123
+ pcall(function()
124
+ return self.port.disconnect()
125
+ end)
126
+ closeClaims(not committed)
127
+ if not committed then
128
+ discardIndices()
129
+ end
130
+ end
131
+ function ClientSession:send(token, value)
132
+ local sendable = self:sendable()
133
+ local definition = toServer(token, "to-server", "Network.send needs a message declared with toServer")
134
+ local body = encodeBody(definition.name, definition.input, "payload", value)
135
+ if not sendable or self.peer.state == 2 then
136
+ return false
137
+ end
138
+ local index = definition.index
139
+ if index == nil then
140
+ self:unpublished(definition)
141
+ return false
142
+ end
143
+ return self:deliver(self.peer, frame(body, 0, { index }))
144
+ end
145
+ function ClientSession:ask(token, value)
146
+ local sendable = self:sendable()
147
+ local definition = toServer(token, "ask-server", "Network.ask needs a message declared with askServer")
148
+ local body = encodeBody(definition.name, definition.input, "request", value)
149
+ if not sendable or self.peer.state == 2 then
150
+ return failed("disconnected")
151
+ end
152
+ local index = definition.index
153
+ if index == nil then
154
+ self:unpublished(definition)
155
+ return failed("unavailable")
156
+ end
157
+ -- ▼ ReadonlyMap.size ▼
158
+ local _size = 0
159
+ for _ in self.pending do
160
+ _size += 1
161
+ end
162
+ -- ▲ ReadonlyMap.size ▲
163
+ if _size >= L.MAX_PENDING_ASKS then
164
+ return failed("overloaded")
165
+ end
166
+ local nonce = self.nextNonce
167
+ local packet = frame(body, 1, { index, nonce })
168
+ self.nextNonce = nonce + 1
169
+ local entry = {
170
+ definition = definition,
171
+ thread = coroutine.running(),
172
+ packet = packet,
173
+ }
174
+ self.pending[nonce] = entry
175
+ entry.deadline = self.port.delay(definition.timeout, function()
176
+ return self:expire(nonce)
177
+ end)
178
+ self:deliver(self.peer, packet)
179
+ if entry.result ~= nil then
180
+ return entry.result
181
+ end
182
+ return (coroutine.yield())
183
+ end
184
+ function ClientSession:fire(_peer, packet)
185
+ self.port.fireServer(packet.bytes, packet.sidecar)
186
+ end
187
+ ClientSession["end"] = function(self, peer)
188
+ if not super["end"](self, peer) then
189
+ return false
190
+ end
191
+ local nonces = {}
192
+ for nonce in self.pending do
193
+ table.insert(nonces, nonce)
194
+ end
195
+ table.sort(nonces)
196
+ for _, nonce in nonces do
197
+ self:settle(nonce, failed("disconnected"))
198
+ end
199
+ return true
200
+ end
201
+ function ClientSession:fail(peer, reason, detail)
202
+ if peer.state == 2 then
203
+ return nil
204
+ end
205
+ runtimeDiagnostic("error", `Crucible network session failed ({FAIL_NAMES[reason + 1]}){if detail == nil then "" else `: {detail}`}`)
206
+ pcall(function()
207
+ return self:fire(peer, controlPacket(5, {}, reason))
208
+ end)
209
+ self["end"](self, peer)
210
+ end
211
+ function ClientSession:unpublished(definition)
212
+ local _unpublishedReported = self.unpublishedReported
213
+ local _definition = definition
214
+ if _unpublishedReported[_definition] ~= nil then
215
+ return nil
216
+ end
217
+ local _unpublishedReported_1 = self.unpublishedReported
218
+ local _definition_1 = definition
219
+ _unpublishedReported_1[_definition_1] = true
220
+ runtimeDiagnostic("warning", `Crucible {definition.name} is not in the server's network catalog`)
221
+ end
222
+ function ClientSession:once(seen, definition, message)
223
+ local _seen = seen
224
+ local _definition = definition
225
+ if _seen[_definition] ~= nil then
226
+ return nil
227
+ end
228
+ local _seen_1 = seen
229
+ local _definition_1 = definition
230
+ _seen_1[_definition_1] = true
231
+ runtimeDiagnostic("warning", message)
232
+ end
233
+ function ClientSession:expire(nonce)
234
+ local _pending = self.pending
235
+ local _nonce = nonce
236
+ local entry = _pending[_nonce]
237
+ if entry == nil then
238
+ return nil
239
+ end
240
+ local _queue = self.peer.queue
241
+ local _packet = entry.packet
242
+ local index = (table.find(_queue, _packet) or 0) - 1
243
+ if index ~= -1 then
244
+ table.remove(self.peer.queue, index + 1)
245
+ self.peer.queuedBytes -= entry.packet.charge
246
+ end
247
+ self:settle(nonce, failed("timeout"))
248
+ end
249
+ function ClientSession:settle(nonce, result)
250
+ local _pending = self.pending
251
+ local _nonce = nonce
252
+ local entry = _pending[_nonce]
253
+ if entry == nil then
254
+ return nil
255
+ end
256
+ local _pending_1 = self.pending
257
+ local _nonce_1 = nonce
258
+ _pending_1[_nonce_1] = nil
259
+ local _result = entry.deadline
260
+ if _result ~= nil then
261
+ _result()
262
+ end
263
+ entry.result = result
264
+ if self.later ~= nil then
265
+ local _exp = self.later
266
+ table.insert(_exp, entry)
267
+ else
268
+ self:resume(entry)
269
+ end
270
+ end
271
+ function ClientSession:resume(entry)
272
+ if coroutine.status(entry.thread) == "suspended" then
273
+ self.port.resume(entry.thread, entry.result)
274
+ end
275
+ end
276
+ function ClientSession:receive(count, packet, sidecar)
277
+ local later = {}
278
+ self.later = later
279
+ local ok, err = pcall(function()
280
+ return self:dispatch(count, packet, sidecar)
281
+ end)
282
+ self.later = nil
283
+ if not ok then
284
+ self:fail(self.peer, 3, `receive failed: {tostring(err)}`)
285
+ end
286
+ for _, entry in later do
287
+ self:resume(entry)
288
+ end
289
+ end
290
+ function ClientSession:violation(detail)
291
+ self:fail(self.peer, 3, detail)
292
+ end
293
+ function ClientSession:dispatch(count, packet, sidecar)
294
+ if self.peer.state == 2 then
295
+ return nil
296
+ end
297
+ local header = readHeader(count, packet, sidecar)
298
+ if header == nil then
299
+ return self:violation("a malformed packet")
300
+ end
301
+ if header.opcode == 5 then
302
+ local _condition = FAIL_NAMES[header.reason + 1]
303
+ if _condition == nil then
304
+ _condition = `unknown reason {header.reason}`
305
+ end
306
+ local reason = _condition
307
+ runtimeDiagnostic("error", `Crucible network session ended: the server sent FAIL ({reason})`)
308
+ self["end"](self, self.peer)
309
+ return nil
310
+ end
311
+ if not self.fired then
312
+ return self:violation("a game packet before READY")
313
+ end
314
+ if header.opcode == 0 then
315
+ return self:event(header, packet, sidecar)
316
+ end
317
+ if header.opcode == 2 or header.opcode == 3 then
318
+ return self:answer(header, packet, sidecar)
319
+ end
320
+ self:violation("a client-to-server packet")
321
+ end
322
+ function ClientSession:event(header, packet, sidecar)
323
+ if header.index >= catalogSize() then
324
+ return self:violation("an unknown message index")
325
+ end
326
+ local definition = definitionAt(header.index)
327
+ if definition == nil then
328
+ local _undeclared = self.undeclared
329
+ local _index = header.index
330
+ if _undeclared[_index] ~= nil then
331
+ return nil
332
+ end
333
+ local _undeclared_1 = self.undeclared
334
+ local _index_1 = header.index
335
+ _undeclared_1[_index_1] = true
336
+ runtimeDiagnostic("warning", `Crucible dropped catalog message {header.index}: this client never declared it`)
337
+ return nil
338
+ end
339
+ if definition.kind ~= "to-client" then
340
+ return self:violation(`{definition.name} sent as an event`)
341
+ end
342
+ local decoded, value = pcall(function()
343
+ return decodeBody(definition.input, "payload", openBody(packet, sidecar, header))
344
+ end)
345
+ if not decoded then
346
+ if missingInstance(value) then
347
+ return self:once(self.missingPlayer, definition, `Crucible dropped {definition.name}: a Player left`)
348
+ end
349
+ return self:violation(`{definition.name} {failureReason(value)}`)
350
+ end
351
+ local receiver = receiverOf(definition)
352
+ if receiver == nil then
353
+ return self:unreceived(definition)
354
+ end
355
+ if self.peer.counted >= L.MAX_ACTIVE_HANDLERS then
356
+ return self:fail(self.peer, 1)
357
+ end
358
+ self:start(self.peer, receiver, { value })
359
+ end
360
+ function ClientSession:answer(header, packet, sidecar)
361
+ local definition = definitionAt(header.index)
362
+ if definition == nil or definition.kind ~= "ask-server" then
363
+ return self:violation("a reply naming a message that is not an ask")
364
+ end
365
+ local _pending = self.pending
366
+ local _nonce = header.nonce
367
+ local entry = _pending[_nonce]
368
+ if entry == nil then
369
+ return self:once(self.unmatched, definition, `Crucible ignored a late or unknown reply to {definition.name}`)
370
+ end
371
+ if entry.definition ~= definition then
372
+ return self:violation(`a reply to {entry.definition.name} naming {definition.name}`)
373
+ end
374
+ if header.opcode == 3 then
375
+ local reason = ERROR_REASONS[header.reason + 1]
376
+ if reason == nil then
377
+ return self:violation(`an unknown ERROR reason {header.reason}`)
378
+ end
379
+ return self:settle(header.nonce, failed(reason))
380
+ end
381
+ local decoded, value = pcall(function()
382
+ return decodeBody(definition.output, "response", openBody(packet, sidecar, header))
383
+ end)
384
+ if not decoded then
385
+ self:once(self.undecoded, definition, `Crucible could not decode a reply to {definition.name}: {failureReason(value)}`)
386
+ return self:settle(header.nonce, failed("invalid"))
387
+ end
388
+ self:settle(header.nonce, table.freeze({
389
+ ok = true,
390
+ value = value,
391
+ }))
392
+ end
393
+ end
394
+ function toServer(token, kind, message)
395
+ local definition = definitionOf(token)
396
+ if definition == nil or definition.kind ~= kind then
397
+ error(message, 0)
398
+ end
399
+ return definition
400
+ end
401
+ return {
402
+ ClientSession = ClientSession,
403
+ }
@@ -0,0 +1,63 @@
1
+ import { type Branch, type Node } from "./schema";
2
+ export interface CodecFailure {
3
+ readonly codecFailure: true;
4
+ readonly path: string;
5
+ readonly reason: string;
6
+ readonly missing?: true;
7
+ }
8
+ export declare class Budget {
9
+ visits: number;
10
+ entries: number;
11
+ depth: number;
12
+ chargeEntries(count: number, path: string): void;
13
+ visit(path: string): void;
14
+ enter(path: string): void;
15
+ leave(): void;
16
+ }
17
+ export declare class Writer {
18
+ readonly budget: Budget;
19
+ readonly slots: Instance[];
20
+ private data;
21
+ private cursor;
22
+ private reserve;
23
+ u8(value: number): void;
24
+ u16(value: number): void;
25
+ u32(value: number): void;
26
+ varuint(value: number): void;
27
+ f32(value: number): void;
28
+ f64(value: number): void;
29
+ bytes(text: string): void;
30
+ slot(instance: Instance): void;
31
+ finish(header: buffer): LuaTuple<[buffer, Readonly<Record<string, Instance>>, number]>;
32
+ }
33
+ export declare class Reader {
34
+ private readonly packet;
35
+ private cursor;
36
+ private readonly sidecar;
37
+ private readonly slotCount;
38
+ readonly budget: Budget;
39
+ private nextSlot;
40
+ constructor(packet: buffer, cursor: number, sidecar: Readonly<Record<string, Instance>>, slotCount: number);
41
+ private take;
42
+ u8(): number;
43
+ u16(): number;
44
+ u32(): number;
45
+ varuint(): number;
46
+ f32(): number;
47
+ f64(): number;
48
+ string(): string;
49
+ count(minElementBytes: number, path: string): number;
50
+ slot(path: string): Instance | undefined;
51
+ finished(): boolean;
52
+ }
53
+ export interface Codec {
54
+ readonly node: Branch;
55
+ readonly minBytes: number;
56
+ readonly encode: (writer: Writer, value: unknown, path: string) => void;
57
+ readonly decode: (reader: Reader, path: string) => unknown;
58
+ }
59
+ export declare function compile(node: Node, tally?: {
60
+ nodes: number;
61
+ }): Codec;
62
+ export declare function encodeDynamic(w: Writer, value: unknown, path: string, active: Set<object>, topLevel?: boolean, arrayElement?: boolean): void;
63
+ export declare function decodeDynamic(r: Reader, path: string, topLevel: boolean, arrayElement?: boolean): unknown;