@trioforge/crucible 0.1.0 → 0.3.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 (145) hide show
  1. package/maths/spline/package.json +4 -0
  2. package/out/client/index.d.ts +7 -0
  3. package/out/client/init.luau +36 -1
  4. package/out/configs.d.ts +37 -0
  5. package/out/configs.luau +46 -0
  6. package/out/data.d.ts +224 -0
  7. package/out/data.luau +97 -0
  8. package/out/emit/configs.d.ts +4 -0
  9. package/out/emit/configs.luau +22 -0
  10. package/out/emit/data.d.ts +6 -0
  11. package/out/emit/data.luau +19 -0
  12. package/out/emit/index.d.ts +5 -1
  13. package/out/emit/init.luau +23 -7
  14. package/out/emit/network.d.ts +6 -0
  15. package/out/emit/network.luau +36 -0
  16. package/out/emit/replicated.d.ts +4 -0
  17. package/out/emit/replicated.luau +13 -0
  18. package/out/index.d.ts +8 -0
  19. package/out/init.luau +23 -0
  20. package/out/internal/binding.luau +5 -0
  21. package/out/internal/boot.luau +112 -8
  22. package/out/internal/configs/limits.d.ts +10 -0
  23. package/out/internal/configs/limits.luau +25 -0
  24. package/out/internal/configs/port.d.ts +29 -0
  25. package/out/internal/configs/port.luau +99 -0
  26. package/out/internal/configs/runtime.d.ts +21 -0
  27. package/out/internal/configs/runtime.luau +981 -0
  28. package/out/internal/data/admission.d.ts +1 -0
  29. package/out/internal/data/admission.luau +673 -0
  30. package/out/internal/data/declarations.d.ts +1 -0
  31. package/out/internal/data/declarations.luau +384 -0
  32. package/out/internal/data/envelope.d.ts +1 -0
  33. package/out/internal/data/envelope.luau +318 -0
  34. package/out/internal/data/handles.d.ts +1 -0
  35. package/out/internal/data/handles.luau +255 -0
  36. package/out/internal/data/inbox-transforms.d.ts +1 -0
  37. package/out/internal/data/inbox-transforms.luau +458 -0
  38. package/out/internal/data/inbox.d.ts +1 -0
  39. package/out/internal/data/inbox.luau +437 -0
  40. package/out/internal/data/lease.d.ts +1 -0
  41. package/out/internal/data/lease.luau +304 -0
  42. package/out/internal/data/limits.d.ts +1 -0
  43. package/out/internal/data/limits.luau +234 -0
  44. package/out/internal/data/messages.d.ts +1 -0
  45. package/out/internal/data/messages.luau +69 -0
  46. package/out/internal/data/operation-id.d.ts +1 -0
  47. package/out/internal/data/operation-id.luau +61 -0
  48. package/out/internal/data/paths.d.ts +2 -0
  49. package/out/internal/data/paths.luau +323 -0
  50. package/out/internal/data/port.d.ts +1 -0
  51. package/out/internal/data/port.luau +290 -0
  52. package/out/internal/data/profiles.d.ts +1 -0
  53. package/out/internal/data/profiles.luau +862 -0
  54. package/out/internal/data/receipts.d.ts +1 -0
  55. package/out/internal/data/receipts.luau +190 -0
  56. package/out/internal/data/record-bindings.d.ts +1 -0
  57. package/out/internal/data/record-bindings.luau +92 -0
  58. package/out/internal/data/record-declarations.d.ts +1 -0
  59. package/out/internal/data/record-declarations.luau +140 -0
  60. package/out/internal/data/records.d.ts +1 -0
  61. package/out/internal/data/records.luau +400 -0
  62. package/out/internal/data/runtime.d.ts +1 -0
  63. package/out/internal/data/runtime.luau +918 -0
  64. package/out/internal/data/scheduler.d.ts +1 -0
  65. package/out/internal/data/scheduler.luau +507 -0
  66. package/out/internal/data/session.d.ts +1 -0
  67. package/out/internal/data/session.luau +234 -0
  68. package/out/internal/data/shutdown.d.ts +1 -0
  69. package/out/internal/data/shutdown.luau +91 -0
  70. package/out/internal/data/waiters.d.ts +1 -0
  71. package/out/internal/data/waiters.luau +65 -0
  72. package/out/internal/lifecycle.luau +45 -0
  73. package/out/internal/network/catalog.d.ts +26 -0
  74. package/out/internal/network/catalog.luau +182 -0
  75. package/out/internal/network/claims.d.ts +1 -0
  76. package/out/internal/network/claims.luau +146 -0
  77. package/out/internal/network/client-session.d.ts +1 -0
  78. package/out/internal/network/client-session.luau +405 -0
  79. package/out/internal/network/codec.d.ts +63 -0
  80. package/out/internal/network/codec.luau +1183 -0
  81. package/out/internal/network/envelope.d.ts +1 -0
  82. package/out/internal/network/envelope.luau +247 -0
  83. package/out/internal/network/limits.d.ts +26 -0
  84. package/out/internal/network/limits.luau +55 -0
  85. package/out/internal/network/port.d.ts +1 -0
  86. package/out/internal/network/port.luau +19 -0
  87. package/out/internal/network/roblox-network-port.d.ts +1 -0
  88. package/out/internal/network/roblox-network-port.luau +105 -0
  89. package/out/internal/network/schema.d.ts +72 -0
  90. package/out/internal/network/schema.luau +386 -0
  91. package/out/internal/network/server-session.d.ts +1 -0
  92. package/out/internal/network/server-session.luau +395 -0
  93. package/out/internal/network/session.d.ts +1 -0
  94. package/out/internal/network/session.luau +266 -0
  95. package/out/internal/reactive/context.d.ts +1 -0
  96. package/out/internal/reactive/context.luau +149 -0
  97. package/out/internal/reactive/flush.d.ts +1 -0
  98. package/out/internal/reactive/flush.luau +355 -0
  99. package/out/internal/reactive/graph.d.ts +1 -0
  100. package/out/internal/reactive/graph.luau +626 -0
  101. package/out/internal/reactive/limits.d.ts +1 -0
  102. package/out/internal/reactive/limits.luau +54 -0
  103. package/out/internal/reactive/ownership.d.ts +1 -0
  104. package/out/internal/reactive/ownership.luau +626 -0
  105. package/out/internal/registry.luau +10 -1
  106. package/out/internal/sync/client-sync.d.ts +1 -0
  107. package/out/internal/sync/client-sync.luau +157 -0
  108. package/out/internal/sync/declarations.d.ts +1 -0
  109. package/out/internal/sync/declarations.luau +276 -0
  110. package/out/internal/sync/frame.d.ts +1 -0
  111. package/out/internal/sync/frame.luau +91 -0
  112. package/out/internal/sync/server-sync.d.ts +1 -0
  113. package/out/internal/sync/server-sync.luau +502 -0
  114. package/out/internal/sync/values.d.ts +1 -0
  115. package/out/internal/sync/values.luau +930 -0
  116. package/out/maths/spline/curve.d.ts +35 -0
  117. package/out/maths/spline/curve.luau +1122 -0
  118. package/out/maths/spline/index.d.ts +2 -0
  119. package/out/maths/spline/init.luau +8 -0
  120. package/out/network.d.ts +66 -0
  121. package/out/network.luau +24 -0
  122. package/out/reactive.d.ts +76 -0
  123. package/out/reactive.luau +136 -0
  124. package/out/replicated.d.ts +38 -0
  125. package/out/replicated.luau +45 -0
  126. package/out/server/data.d.ts +54 -0
  127. package/out/server/data.luau +44 -0
  128. package/out/server/index.d.ts +17 -0
  129. package/out/server/init.luau +58 -4
  130. package/out/server/publish.d.ts +20 -0
  131. package/out/server/publish.luau +24 -0
  132. package/out/testing/index.d.ts +38 -0
  133. package/out/testing/init.luau +189 -0
  134. package/out/util/random/index.d.ts +24 -0
  135. package/out/util/random/init.luau +301 -0
  136. package/out/vide/index.d.ts +7 -0
  137. package/out/vide/init.luau +50 -0
  138. package/package.json +28 -2
  139. package/testing/package.json +4 -0
  140. package/transformer/data.cjs +72 -0
  141. package/transformer/declarations.cjs +153 -0
  142. package/transformer/index.js +87 -23
  143. package/transformer/network.cjs +961 -0
  144. package/util/random/package.json +4 -0
  145. package/vide/package.json +4 -0
@@ -0,0 +1,157 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local Subsystem = TS.import(script, script.Parent.Parent.Parent, "subsystem").Subsystem
4
+ local runtimeDiagnostic = TS.import(script, script.Parent.Parent, "diagnostics").runtimeDiagnostic
5
+ local claim = TS.import(script, script.Parent.Parent, "network", "claims").claim
6
+ local commitPrepared = TS.import(script, script.Parent.Parent, "reactive", "graph").commitPrepared
7
+ local define = TS.import(script, script.Parent.Parent, "registry").define
8
+ local _declarations = TS.import(script, script.Parent, "declarations")
9
+ local declarationNamed = _declarations.declarationNamed
10
+ local declarations = _declarations.declarations
11
+ local SyncFrameMessage = TS.import(script, script.Parent, "frame").SyncFrameMessage
12
+ local reuse = TS.import(script, script.Parent, "values").reuse
13
+ --* @internal How ClientSync reports its last applied revision: exactly `Network.send` on the fault message.
14
+ local sendFault = function() end
15
+ local function ascending(keys)
16
+ for i = 1, #keys - 1 do
17
+ if not (keys[i] < keys[i + 1]) then
18
+ return false
19
+ end
20
+ end
21
+ return true
22
+ end
23
+ local function disjoint(values, failed)
24
+ local i = 0
25
+ local j = 0
26
+ while i < #values and j < #failed do
27
+ if values[i + 1] == failed[j + 1] then
28
+ return false
29
+ end
30
+ if values[i + 1] < failed[j + 1] then
31
+ i += 1
32
+ else
33
+ j += 1
34
+ end
35
+ end
36
+ return true
37
+ end
38
+ local ClientSync
39
+ do
40
+ local super = Subsystem
41
+ ClientSync = setmetatable({}, {
42
+ __tostring = function()
43
+ return "ClientSync"
44
+ end,
45
+ __index = super,
46
+ })
47
+ ClientSync.__index = ClientSync
48
+ function ClientSync.new(...)
49
+ local self = setmetatable({}, ClientSync)
50
+ return self:constructor(...) or self
51
+ end
52
+ function ClientSync:constructor(...)
53
+ super.constructor(self, ...)
54
+ self.revision = 0
55
+ self.snapshotted = false
56
+ self.failed = false
57
+ self.frames = claim(self, "frames", SyncFrameMessage, function(frame)
58
+ return self:apply(frame)
59
+ end)
60
+ end
61
+ function ClientSync:apply(frame)
62
+ if self.failed then
63
+ return nil
64
+ end
65
+ if frame.kind == "failed" then
66
+ return self:latch(`the server stopped this client's sync at revision {frame.revision}`, false)
67
+ end
68
+ local _exp = frame.values
69
+ -- ▼ ReadonlyArray.map ▼
70
+ local _newValue = table.create(#_exp)
71
+ local _callback = function(entry)
72
+ return entry.key
73
+ end
74
+ for _k, _v in _exp do
75
+ _newValue[_k] = _callback(_v, _k - 1, _exp)
76
+ end
77
+ -- ▲ ReadonlyArray.map ▲
78
+ local keys = _newValue
79
+ if if frame.kind == "snapshot" then self.snapshotted or frame.revision ~= 1 else not self.snapshotted then
80
+ return self:latch(`unexpected {frame.kind} at revision {frame.revision} after {self.revision}`, true)
81
+ end
82
+ if frame.kind == "update" and frame.revision ~= self.revision + 1 then
83
+ return self:latch(`revision {frame.revision} does not follow {self.revision}`, true)
84
+ end
85
+ if not ascending(keys) or not ascending(frame.failed) or not disjoint(keys, frame.failed) then
86
+ return self:latch(`revision {frame.revision} lists keys out of order or twice`, true)
87
+ end
88
+ local prepared, writes = pcall(function()
89
+ local out = {}
90
+ for _, entry in frame.values do
91
+ local declaration = declarationNamed(entry.key)
92
+ if declaration == nil then
93
+ continue
94
+ end
95
+ local reused = reuse(declaration.node.value, entry.value)
96
+ if not rawequal(reused, declaration.node.value) then
97
+ local _arg0 = { declaration.node, reused }
98
+ table.insert(out, _arg0)
99
+ end
100
+ local _arg0 = { declaration.status, "ready" }
101
+ table.insert(out, _arg0)
102
+ end
103
+ for _, key in frame.failed do
104
+ local declaration = declarationNamed(key)
105
+ if declaration ~= nil then
106
+ local _arg0 = { declaration.status, "failed" }
107
+ table.insert(out, _arg0)
108
+ end
109
+ end
110
+ return out
111
+ end)
112
+ if not prepared then
113
+ return self:latch(`internal error while preparing revision {frame.revision}: {tostring(writes)}`, true)
114
+ end
115
+ commitPrepared(writes)
116
+ self.snapshotted = true
117
+ self.revision = frame.revision
118
+ end
119
+ function ClientSync:latch(reason, fault)
120
+ self.failed = true
121
+ local _, err = pcall(function()
122
+ local _exp = declarations()
123
+ -- ▼ ReadonlyArray.map ▼
124
+ local _newValue = table.create(#_exp)
125
+ local _callback = function(declaration)
126
+ return { declaration.status, "failed" }
127
+ end
128
+ for _k, _v in _exp do
129
+ _newValue[_k] = _callback(_v, _k - 1, _exp)
130
+ end
131
+ -- ▲ ReadonlyArray.map ▲
132
+ return commitPrepared(_newValue)
133
+ end)
134
+ if fault then
135
+ pcall(sendFault, self.revision)
136
+ end
137
+ runtimeDiagnostic("error", `Crucible sync stopped: {reason}{if err == nil then "" else `; failing statuses: {tostring(err)}`}`)
138
+ end
139
+ end
140
+ local installed = false
141
+ --* @internal Rule 56: the client entry defines ClientSync once per realm, constructed before every game Subsystem.
142
+ local function installClientSync(fault)
143
+ sendFault = fault
144
+ if installed then
145
+ return nil
146
+ end
147
+ installed = true
148
+ define(ClientSync, {
149
+ kind = "subsystem",
150
+ id = "Crucible.ClientSync",
151
+ deps = {},
152
+ provides = {},
153
+ }, true)
154
+ end
155
+ return {
156
+ installClientSync = installClientSync,
157
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,276 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local readClaim = TS.import(script, script.Parent.Parent, "construction-claim").readClaim
4
+ local compile = TS.import(script, script.Parent.Parent, "network", "codec").compile
5
+ local MESSAGE_NAME_MAX_BYTES = TS.import(script, script.Parent.Parent, "network", "limits").MESSAGE_NAME_MAX_BYTES
6
+ local assertDescriptor = TS.import(script, script.Parent.Parent, "network", "schema").assertDescriptor
7
+ local _graph = TS.import(script, script.Parent.Parent, "reactive", "graph")
8
+ local createStateNode = _graph.createStateNode
9
+ local guardPure = _graph.guardPure
10
+ local readState = _graph.readState
11
+ local readUntracked = _graph.readUntracked
12
+ local write = _graph.write
13
+ local MAX_REPLICATED_DECLARATIONS = TS.import(script, script.Parent.Parent, "reactive", "limits").MAX_REPLICATED_DECLARATIONS
14
+ local _values = TS.import(script, script.Parent, "values")
15
+ local admit = _values.admit
16
+ local compilePlan = _values.compilePlan
17
+ --* @internal
18
+ --* @internal
19
+ --* @internal One declaration's server write side (rules 47 to 54).
20
+ --* @internal
21
+ local byName = {}
22
+ local handles = setmetatable({}, {
23
+ __mode = "k",
24
+ })
25
+ local ordered = {}
26
+ local sealed = false
27
+ local onRetired = function() end
28
+ local function onServer()
29
+ return game:GetService("RunService"):IsServer()
30
+ end
31
+ local function perPlayer(declaration)
32
+ error(`{declaration.name} is per player; on the server, read the sources its publisher projects from`, 0)
33
+ end
34
+ local function checkName(name, framework)
35
+ local grammar = `use 1 to {MESSAGE_NAME_MAX_BYTES} bytes of dot-separated [A-Za-z][A-Za-z0-9_]* segments`
36
+ local _name = name
37
+ local _condition = not (type(_name) == "string")
38
+ if not _condition then
39
+ _condition = #name == 0 or #name > MESSAGE_NAME_MAX_BYTES
40
+ end
41
+ if _condition then
42
+ error(`Crucible replicated name {tostring(name)} is invalid: {grammar}`, 0)
43
+ end
44
+ local segments = string.split(name, ".")
45
+ for _, segment in segments do
46
+ if (string.match(segment, "^[A-Za-z][A-Za-z0-9_]*$")) == nil then
47
+ error(`Crucible replicated name {name} is invalid: {grammar}`, 0)
48
+ end
49
+ end
50
+ if (segments[1] == "Crucible") ~= framework then
51
+ error(if framework then `Crucible replicated name {name} is invalid: a framework declaration starts with Crucible.` else `Crucible replicated name {name} is invalid: Crucible. is reserved`, 0)
52
+ end
53
+ end
54
+ local function register(audience, name, initial, descriptor)
55
+ if sealed then
56
+ error(`{name} was declared after the replicated registry sealed; declare replicated state in modules that boot loads`, 0)
57
+ end
58
+ local _name = name
59
+ if byName[_name] ~= nil then
60
+ error(`Crucible replicated name {name} is declared twice`, 0)
61
+ end
62
+ -- ▼ ReadonlyMap.size ▼
63
+ local _size = 0
64
+ for _ in byName do
65
+ _size += 1
66
+ end
67
+ -- ▲ ReadonlyMap.size ▲
68
+ if _size >= MAX_REPLICATED_DECLARATIONS then
69
+ error(`{name} would pass {MAX_REPLICATED_DECLARATIONS} replicated declarations in this realm`, 0)
70
+ end
71
+ assertDescriptor(descriptor)
72
+ compile(descriptor)
73
+ local plan = compilePlan(descriptor)
74
+ local admitted = admit(plan, name, initial)
75
+ local declaration = {
76
+ name = name,
77
+ audience = audience,
78
+ plan = plan,
79
+ initial = admitted,
80
+ node = createStateNode(admitted),
81
+ status = createStateNode("pending"),
82
+ }
83
+ local _name_1 = name
84
+ byName[_name_1] = declaration
85
+ table.insert(ordered, declaration)
86
+ table.sort(ordered, function(a, b)
87
+ return a.name < b.name
88
+ end)
89
+ local handle = if audience == "all" then function()
90
+ return readState(declaration.node)
91
+ end else function()
92
+ return if onServer() then perPlayer(declaration) else readState(declaration.node)
93
+ end
94
+ handles[handle] = declaration
95
+ return handle
96
+ end
97
+ --* @internal The emitted `replicated` and `replicatedPerPlayer` (rules 40, 41, 78).
98
+ local function declareReplicated(audience, name, initial, descriptor)
99
+ checkName(name, false)
100
+ return register(audience, name, initial, descriptor)
101
+ end
102
+ --[[
103
+ *
104
+ * @internal
105
+ * R-D1 (data rule 133): a per-player declaration only the framework makes, under the reserved `Crucible.` segment.
106
+ * It counts against MAX_REPLICATED_DECLARATIONS and the duplicate check like any other.
107
+
108
+ ]]
109
+ local function declareFrameworkReplicated(name, initial, descriptor)
110
+ checkName(name, true)
111
+ return register("player", name, initial, descriptor)
112
+ end
113
+ --* @internal How many more replicated declarations this realm admits (data rule 134).
114
+ local function replicatedCapacity()
115
+ -- ▼ ReadonlyMap.size ▼
116
+ local _size = 0
117
+ for _ in byName do
118
+ _size += 1
119
+ end
120
+ -- ▲ ReadonlyMap.size ▲
121
+ return MAX_REPLICATED_DECLARATIONS - _size
122
+ end
123
+ --* @internal
124
+ local function declarationOf(handle)
125
+ local _handle = handle
126
+ return handles[_handle]
127
+ end
128
+ --* @internal
129
+ local function declarationNamed(name)
130
+ local _name = name
131
+ return byName[_name]
132
+ end
133
+ --* @internal Every declaration in this realm, by name in byte order.
134
+ local function declarations()
135
+ return ordered
136
+ end
137
+ --* @internal `syncStatus` (rule 45): a tracked read of the status node.
138
+ local function statusOf(handle)
139
+ local declaration = declarationOf(handle) or error("syncStatus takes a replicated declaration", 0)
140
+ if declaration.audience == "player" and onServer() then
141
+ perPlayer(declaration)
142
+ end
143
+ return readState(declaration.status)
144
+ end
145
+ --* @internal ServerSync registers how a retirement reaches every peer (rule 52).
146
+ local function useRetired(listener)
147
+ onRetired = listener
148
+ end
149
+ local function retire(declaration, publication)
150
+ if not publication.live then
151
+ return nil
152
+ end
153
+ publication.live = false
154
+ if declaration.audience == "all" then
155
+ write(declaration.status, "failed")
156
+ end
157
+ onRetired(declaration)
158
+ end
159
+ local function ended(declaration, publication)
160
+ error(`{declaration.name}'s publisher {publication.label} has ended`, 0)
161
+ end
162
+ local publishedMethods = {
163
+ set = function(self, value)
164
+ guardPure("write state")
165
+ local _binding = self
166
+ local declaration = _binding.declaration
167
+ local publication = _binding.publication
168
+ if not publication.live then
169
+ ended(declaration, publication)
170
+ end
171
+ write(declaration.node, admit(declaration.plan, declaration.name, value))
172
+ end,
173
+ update = function(self, change)
174
+ guardPure("write state")
175
+ local _binding = self
176
+ local declaration = _binding.declaration
177
+ local publication = _binding.publication
178
+ if not publication.live then
179
+ ended(declaration, publication)
180
+ end
181
+ local changed = readUntracked(function()
182
+ return change(declaration.node.value)
183
+ end, "update's callback")
184
+ if not publication.live then
185
+ ended(declaration, publication)
186
+ end
187
+ write(declaration.node, admit(declaration.plan, declaration.name, changed))
188
+ end,
189
+ }
190
+ local publishedMeta = {
191
+ __index = publishedMethods,
192
+ __call = function(handle)
193
+ return readState(handle.declaration.node)
194
+ end,
195
+ }
196
+ --* @internal `publish`'s runtime half (rules 47 to 50).
197
+ local function claimPublication(target, project)
198
+ local owner = readClaim()
199
+ if owner == nil or owner.record.kind ~= 0 then
200
+ error("publish runs while a server Subsystem is constructed; make it a field initializer", 0)
201
+ end
202
+ local declaration = declarationOf(target) or error("publish takes a replicated declaration", 0)
203
+ local label = (owner.record).id
204
+ local previous = declaration.publication
205
+ if previous ~= nil then
206
+ error(`{declaration.name} is published by {previous.label} and {label}; one Subsystem publishes each value`, 0)
207
+ end
208
+ if (declaration.audience == "player") ~= (project ~= nil) then
209
+ error(if declaration.audience == "player" then `{declaration.name} is per player; publish it with a projection` else `{declaration.name} is public; publish it without a projection`, 0)
210
+ end
211
+ local _condition = project ~= nil
212
+ if _condition then
213
+ local _project = project
214
+ _condition = not (type(_project) == "function")
215
+ end
216
+ if _condition then
217
+ error(`{declaration.name}: publish needs a projection function`, 0)
218
+ end
219
+ local publication = {
220
+ label = label,
221
+ project = project,
222
+ live = true,
223
+ }
224
+ declaration.publication = publication
225
+ if owner.subscriptions == nil then
226
+ owner.subscriptions = {}
227
+ end
228
+ local _exp = owner.subscriptions
229
+ table.insert(_exp, function()
230
+ return retire(declaration, publication)
231
+ end)
232
+ if declaration.audience == "player" then
233
+ return table.freeze({})
234
+ end
235
+ write(declaration.status, "ready")
236
+ return setmetatable({
237
+ declaration = declaration,
238
+ publication = publication,
239
+ }, publishedMeta)
240
+ end
241
+ --* @internal The server's registry seals with the catalog; the client's at its network commit (rule 41).
242
+ local function sealDeclarations()
243
+ sealed = true
244
+ end
245
+ --[[
246
+ *
247
+ * @internal
248
+ * Rule 74: retire every publication silently, restore every value to its admitted `initial` and status to
249
+ * "pending", and unseal. Declarations stay registered, because their modules stay cached.
250
+
251
+ ]]
252
+ local function rollbackDeclarations()
253
+ for _, declaration in ordered do
254
+ local publication = declaration.publication
255
+ if publication ~= nil then
256
+ publication.live = false
257
+ end
258
+ declaration.publication = nil
259
+ write(declaration.node, declaration.initial)
260
+ write(declaration.status, "pending")
261
+ end
262
+ sealed = false
263
+ end
264
+ return {
265
+ declareReplicated = declareReplicated,
266
+ declareFrameworkReplicated = declareFrameworkReplicated,
267
+ replicatedCapacity = replicatedCapacity,
268
+ declarationOf = declarationOf,
269
+ declarationNamed = declarationNamed,
270
+ declarations = declarations,
271
+ statusOf = statusOf,
272
+ useRetired = useRetired,
273
+ claimPublication = claimPublication,
274
+ sealDeclarations = sealDeclarations,
275
+ rollbackDeclarations = rollbackDeclarations,
276
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,91 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local defineFramework = TS.import(script, script.Parent.Parent, "network", "catalog").defineFramework
4
+ local n = TS.import(script, script.Parent.Parent, "network", "schema").n
5
+ local _limits = TS.import(script, script.Parent.Parent, "reactive", "limits")
6
+ local SYNC_FRAME_BYTES = _limits.SYNC_FRAME_BYTES
7
+ local SYNC_FRAME_COLLECTION_ENTRIES = _limits.SYNC_FRAME_COLLECTION_ENTRIES
8
+ local SYNC_FRAME_VALUE_VISITS = _limits.SYNC_FRAME_VALUE_VISITS
9
+ local costOf = TS.import(script, script.Parent, "values").costOf
10
+ --* @internal One declaration's whole value in a frame. A nil `value` is a real root `undefined`.
11
+ --* @internal One atomic observation unit for one peer. Both lists are strictly ascending by key.
12
+ --* @internal
13
+ local SyncFrameMessage = defineFramework({
14
+ kind = "to-client",
15
+ name = "Crucible.State.Frame",
16
+ input = n.object({ { "failed", n.array(n.string) }, { "kind", n.union({ n.literal("failed"), n.literal("snapshot"), n.literal("update") }) }, { "revision", n.u32 }, { "values", n.array(n.object({ { "key", n.string }, { "value", n.dynamic } })) } }),
17
+ })
18
+ --* @internal The last revision a client applied before its sync stopped.
19
+ local SyncFaultMessage = defineFramework({
20
+ kind = "to-server",
21
+ name = "Crucible.State.Fault",
22
+ input = n.u32,
23
+ })
24
+ local function varuintSize(value)
25
+ local size = 1
26
+ while value >= 128 do
27
+ value = math.floor(value / 128)
28
+ size += 1
29
+ end
30
+ return size
31
+ end
32
+ local function stringBytes(text)
33
+ return varuintSize(#text) + #text
34
+ end
35
+ --* @internal The whole EVENT packet `send` encodes for `frame`, with visits and entries as the decoder counts them.
36
+ --[[
37
+ *
38
+ * @internal
39
+ * Rule 69: the envelope (opcode, catalog index, slot count 0), then the frame object, `failed`, the kind's union
40
+ * selection and literal, the u32 revision, and each value entry with its value's cached admission cost.
41
+
42
+ ]]
43
+ local function frameCost(frame, catalogIndex)
44
+ local bytes = 1 + varuintSize(catalogIndex) + 1
45
+ local entries = #frame.failed + #frame.values
46
+ local visits = 1
47
+ visits += 1
48
+ bytes += varuintSize(#frame.failed)
49
+ for _, key in frame.failed do
50
+ visits += 1
51
+ bytes += stringBytes(key)
52
+ end
53
+ visits += 2
54
+ bytes += 1
55
+ visits += 1
56
+ bytes += 4
57
+ visits += 1
58
+ bytes += varuintSize(#frame.values)
59
+ for _, entry in frame.values do
60
+ visits += 2
61
+ bytes += stringBytes(entry.key)
62
+ local cost = costOf(entry.value)
63
+ bytes += cost.bytes
64
+ entries += cost.entries
65
+ visits += cost.visits
66
+ end
67
+ return {
68
+ bytes = bytes,
69
+ entries = entries,
70
+ visits = visits,
71
+ }
72
+ end
73
+ --* @internal The first frame budget `cost` passes, or undefined when it fits.
74
+ local function overBudget(cost)
75
+ if cost.bytes > SYNC_FRAME_BYTES then
76
+ return "SYNC_FRAME_BYTES"
77
+ end
78
+ if cost.entries > SYNC_FRAME_COLLECTION_ENTRIES then
79
+ return "SYNC_FRAME_COLLECTION_ENTRIES"
80
+ end
81
+ if cost.visits > SYNC_FRAME_VALUE_VISITS then
82
+ return "SYNC_FRAME_VALUE_VISITS"
83
+ end
84
+ return nil
85
+ end
86
+ return {
87
+ frameCost = frameCost,
88
+ overBudget = overBudget,
89
+ SyncFrameMessage = SyncFrameMessage,
90
+ SyncFaultMessage = SyncFaultMessage,
91
+ }
@@ -0,0 +1 @@
1
+ export {};