@trioforge/crucible 0.1.0 → 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 (134) hide show
  1. package/out/client/index.d.ts +7 -0
  2. package/out/client/init.luau +36 -1
  3. package/out/configs.d.ts +37 -0
  4. package/out/configs.luau +46 -0
  5. package/out/data.d.ts +224 -0
  6. package/out/data.luau +97 -0
  7. package/out/emit/configs.d.ts +4 -0
  8. package/out/emit/configs.luau +22 -0
  9. package/out/emit/data.d.ts +6 -0
  10. package/out/emit/data.luau +19 -0
  11. package/out/emit/index.d.ts +5 -1
  12. package/out/emit/init.luau +23 -7
  13. package/out/emit/network.d.ts +6 -0
  14. package/out/emit/network.luau +36 -0
  15. package/out/emit/replicated.d.ts +4 -0
  16. package/out/emit/replicated.luau +13 -0
  17. package/out/index.d.ts +8 -0
  18. package/out/init.luau +23 -0
  19. package/out/internal/binding.luau +5 -0
  20. package/out/internal/boot.luau +107 -8
  21. package/out/internal/configs/limits.d.ts +10 -0
  22. package/out/internal/configs/limits.luau +25 -0
  23. package/out/internal/configs/port.d.ts +29 -0
  24. package/out/internal/configs/port.luau +99 -0
  25. package/out/internal/configs/runtime.d.ts +21 -0
  26. package/out/internal/configs/runtime.luau +981 -0
  27. package/out/internal/data/admission.d.ts +1 -0
  28. package/out/internal/data/admission.luau +673 -0
  29. package/out/internal/data/declarations.d.ts +1 -0
  30. package/out/internal/data/declarations.luau +384 -0
  31. package/out/internal/data/envelope.d.ts +1 -0
  32. package/out/internal/data/envelope.luau +318 -0
  33. package/out/internal/data/handles.d.ts +1 -0
  34. package/out/internal/data/handles.luau +255 -0
  35. package/out/internal/data/inbox-transforms.d.ts +1 -0
  36. package/out/internal/data/inbox-transforms.luau +458 -0
  37. package/out/internal/data/inbox.d.ts +1 -0
  38. package/out/internal/data/inbox.luau +437 -0
  39. package/out/internal/data/lease.d.ts +1 -0
  40. package/out/internal/data/lease.luau +304 -0
  41. package/out/internal/data/limits.d.ts +1 -0
  42. package/out/internal/data/limits.luau +234 -0
  43. package/out/internal/data/messages.d.ts +1 -0
  44. package/out/internal/data/messages.luau +69 -0
  45. package/out/internal/data/operation-id.d.ts +1 -0
  46. package/out/internal/data/operation-id.luau +61 -0
  47. package/out/internal/data/paths.d.ts +2 -0
  48. package/out/internal/data/paths.luau +323 -0
  49. package/out/internal/data/port.d.ts +1 -0
  50. package/out/internal/data/port.luau +290 -0
  51. package/out/internal/data/profiles.d.ts +1 -0
  52. package/out/internal/data/profiles.luau +862 -0
  53. package/out/internal/data/receipts.d.ts +1 -0
  54. package/out/internal/data/receipts.luau +190 -0
  55. package/out/internal/data/record-bindings.d.ts +1 -0
  56. package/out/internal/data/record-bindings.luau +92 -0
  57. package/out/internal/data/record-declarations.d.ts +1 -0
  58. package/out/internal/data/record-declarations.luau +140 -0
  59. package/out/internal/data/records.d.ts +1 -0
  60. package/out/internal/data/records.luau +400 -0
  61. package/out/internal/data/runtime.d.ts +1 -0
  62. package/out/internal/data/runtime.luau +918 -0
  63. package/out/internal/data/scheduler.d.ts +1 -0
  64. package/out/internal/data/scheduler.luau +507 -0
  65. package/out/internal/data/session.d.ts +1 -0
  66. package/out/internal/data/session.luau +234 -0
  67. package/out/internal/data/shutdown.d.ts +1 -0
  68. package/out/internal/data/shutdown.luau +91 -0
  69. package/out/internal/data/waiters.d.ts +1 -0
  70. package/out/internal/data/waiters.luau +65 -0
  71. package/out/internal/lifecycle.luau +45 -0
  72. package/out/internal/network/catalog.d.ts +26 -0
  73. package/out/internal/network/catalog.luau +182 -0
  74. package/out/internal/network/claims.d.ts +1 -0
  75. package/out/internal/network/claims.luau +154 -0
  76. package/out/internal/network/client-session.d.ts +1 -0
  77. package/out/internal/network/client-session.luau +403 -0
  78. package/out/internal/network/codec.d.ts +63 -0
  79. package/out/internal/network/codec.luau +1183 -0
  80. package/out/internal/network/envelope.d.ts +1 -0
  81. package/out/internal/network/envelope.luau +247 -0
  82. package/out/internal/network/limits.d.ts +26 -0
  83. package/out/internal/network/limits.luau +55 -0
  84. package/out/internal/network/port.d.ts +1 -0
  85. package/out/internal/network/port.luau +19 -0
  86. package/out/internal/network/roblox-network-port.d.ts +1 -0
  87. package/out/internal/network/roblox-network-port.luau +105 -0
  88. package/out/internal/network/schema.d.ts +72 -0
  89. package/out/internal/network/schema.luau +386 -0
  90. package/out/internal/network/server-session.d.ts +1 -0
  91. package/out/internal/network/server-session.luau +393 -0
  92. package/out/internal/network/session.d.ts +1 -0
  93. package/out/internal/network/session.luau +266 -0
  94. package/out/internal/reactive/context.d.ts +1 -0
  95. package/out/internal/reactive/context.luau +149 -0
  96. package/out/internal/reactive/flush.d.ts +1 -0
  97. package/out/internal/reactive/flush.luau +355 -0
  98. package/out/internal/reactive/graph.d.ts +1 -0
  99. package/out/internal/reactive/graph.luau +626 -0
  100. package/out/internal/reactive/limits.d.ts +1 -0
  101. package/out/internal/reactive/limits.luau +54 -0
  102. package/out/internal/reactive/ownership.d.ts +1 -0
  103. package/out/internal/reactive/ownership.luau +626 -0
  104. package/out/internal/registry.luau +10 -1
  105. package/out/internal/sync/client-sync.d.ts +1 -0
  106. package/out/internal/sync/client-sync.luau +157 -0
  107. package/out/internal/sync/declarations.d.ts +1 -0
  108. package/out/internal/sync/declarations.luau +276 -0
  109. package/out/internal/sync/frame.d.ts +1 -0
  110. package/out/internal/sync/frame.luau +91 -0
  111. package/out/internal/sync/server-sync.d.ts +1 -0
  112. package/out/internal/sync/server-sync.luau +502 -0
  113. package/out/internal/sync/values.d.ts +1 -0
  114. package/out/internal/sync/values.luau +930 -0
  115. package/out/network.d.ts +66 -0
  116. package/out/network.luau +24 -0
  117. package/out/reactive.d.ts +76 -0
  118. package/out/reactive.luau +136 -0
  119. package/out/replicated.d.ts +38 -0
  120. package/out/replicated.luau +45 -0
  121. package/out/server/data.d.ts +54 -0
  122. package/out/server/data.luau +44 -0
  123. package/out/server/index.d.ts +16 -0
  124. package/out/server/init.luau +49 -3
  125. package/out/server/publish.d.ts +20 -0
  126. package/out/server/publish.luau +24 -0
  127. package/out/vide/index.d.ts +7 -0
  128. package/out/vide/init.luau +50 -0
  129. package/package.json +13 -2
  130. package/transformer/data.cjs +72 -0
  131. package/transformer/declarations.cjs +153 -0
  132. package/transformer/index.js +37 -11
  133. package/transformer/network.cjs +961 -0
  134. package/vide/package.json +4 -0
@@ -0,0 +1,255 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local _graph = TS.import(script, script.Parent.Parent, "reactive", "graph")
4
+ local createComputedNode = _graph.createComputedNode
5
+ local readComputed = _graph.readComputed
6
+ local _paths = TS.import(script, script.Parent, "paths")
7
+ local childNode = _paths.childNode
8
+ local describePath = _paths.describePath
9
+ local getPath = _paths.getPath
10
+ local luaKey = _paths.luaKey
11
+ local setPath = _paths.setPath
12
+ local tableBranch = _paths.tableBranch
13
+ --[[
14
+ *
15
+ * @internal What a tree of handles reads from and writes to: a player's slot on the server, an inert source for a
16
+ * player who is not present, or the owner's views on the client (rules 115, 117, 124, 126).
17
+
18
+ ]]
19
+ --* The node lives in each handle's own metatable: Luau's weak keys are not ephemerons, so no shared table maps them.
20
+ local NODE = {}
21
+ local RESERVED = {
22
+ ["set"] = true,
23
+ ["update"] = true,
24
+ ["insert"] = true,
25
+ ["remove"] = true,
26
+ }
27
+ local function nodeOf(target)
28
+ local _target = target
29
+ if not (type(_target) == "table") then
30
+ return nil
31
+ end
32
+ local meta = getmetatable(target)
33
+ return if type(meta) == "table" then (meta[NODE]) else nil
34
+ end
35
+ local function mapKey(name)
36
+ error(`a map key named "{name}" has no handle; read the map and write it with the map's update`, 3)
37
+ end
38
+ local function writer(handle, method)
39
+ local node = nodeOf(handle)
40
+ if node == nil then
41
+ mapKey(method)
42
+ end
43
+ return node
44
+ end
45
+ --* Rule 118: the parent of the written position exists and is a table, and an index is an integer in range.
46
+ local function check(node, root, path, extra)
47
+ local name = node.source.name
48
+ local parent = root
49
+ for i = 0, #path - 2 do
50
+ parent = parent[luaKey(path[i + 1])]
51
+ local _parent = parent
52
+ if not (type(_parent) == "table") then
53
+ error(`{describePath(name, path)}: its parent does not exist; set the parent whole`, 0)
54
+ end
55
+ end
56
+ local last = path[#path]
57
+ if type(last) == "number" then
58
+ local highest = #parent - 1 + extra
59
+ if last % 1 ~= 0 or last < 0 or last > highest then
60
+ error(`{describePath(name, path)}: {if highest < 0 then "the array is empty" else `the index is not an integer from 0 to {highest}`}`, 0)
61
+ end
62
+ end
63
+ return parent
64
+ end
65
+ local function method(name, run)
66
+ return setmetatable({}, {
67
+ __call = function(_, handle, ...)
68
+ local args = { ... }
69
+ return run(writer(handle, name), unpack(args))
70
+ end,
71
+ __index = function()
72
+ return mapKey(name)
73
+ end,
74
+ __newindex = function()
75
+ return mapKey(name)
76
+ end,
77
+ })
78
+ end
79
+ --* The four write members, shared by every server handle (rules 118 to 120, 122).
80
+ local arrayAt
81
+ local METHODS = {
82
+ set = method("set", function(node, value)
83
+ return node.source:write(function(root)
84
+ if #node.path > 0 then
85
+ check(node, root, node.path, 0)
86
+ end
87
+ return setPath(root, node.path, value)
88
+ end)
89
+ end),
90
+ update = method("update", function(node, change)
91
+ return node.source:write(function(root)
92
+ if #node.path > 0 then
93
+ check(node, root, node.path, 0)
94
+ end
95
+ return setPath(root, node.path, change(getPath(root, node.path)))
96
+ end)
97
+ end),
98
+ insert = method("insert", function(node, value, index)
99
+ return node.source:write(function(root)
100
+ local array = arrayAt(node, root)
101
+ local position = if index == nil then #array else index
102
+ local _exp = node
103
+ local _exp_1 = root
104
+ local _array = {}
105
+ local _length = #_array
106
+ local _array_1 = node.path
107
+ local _Length = #_array_1
108
+ table.move(_array_1, 1, _Length, _length + 1, _array)
109
+ _length += _Length
110
+ _array[_length + 1] = position
111
+ check(_exp, _exp_1, _array, 1)
112
+ local copy = table.clone(array)
113
+ local _value = value
114
+ table.insert(copy, position + 1, _value)
115
+ return setPath(root, node.path, copy)
116
+ end)
117
+ end),
118
+ remove = method("remove", function(node, index)
119
+ return node.source:write(function(root)
120
+ local array = arrayAt(node, root)
121
+ local _exp = node
122
+ local _exp_1 = root
123
+ local _array = {}
124
+ local _length = #_array
125
+ local _array_1 = node.path
126
+ local _Length = #_array_1
127
+ table.move(_array_1, 1, _Length, _length + 1, _array)
128
+ _length += _Length
129
+ _array[_length + 1] = index
130
+ check(_exp, _exp_1, _array, 0)
131
+ local copy = table.clone(array)
132
+ local _index = index
133
+ table.remove(copy, _index + 1)
134
+ return setPath(root, node.path, copy)
135
+ end)
136
+ end),
137
+ }
138
+ function arrayAt(node, root)
139
+ local value = getPath(root, node.path)
140
+ if not (type(value) == "table") then
141
+ error(`{describePath(node.source.name, node.path)}: it does not exist; set it whole`, 0)
142
+ end
143
+ return value
144
+ end
145
+ local makeHandle
146
+ local function child(parent, node, key)
147
+ local schema = childNode(node.schema, key)
148
+ local _condition = schema ~= nil
149
+ if _condition then
150
+ local _result = tableBranch(node.schema)
151
+ if _result ~= nil then
152
+ _result = _result.kind
153
+ end
154
+ _condition = _result == "object"
155
+ end
156
+ local strong = _condition
157
+ local cache = if strong then node.fields else node.entries
158
+ local _key = key
159
+ local found = cache[_key]
160
+ if found ~= nil then
161
+ return found
162
+ end
163
+ local _object = {
164
+ source = node.source,
165
+ }
166
+ local _left = "path"
167
+ local _array = {}
168
+ local _length = #_array
169
+ local _array_1 = node.path
170
+ local _Length = #_array_1
171
+ table.move(_array_1, 1, _Length, _length + 1, _array)
172
+ _length += _Length
173
+ _array[_length + 1] = key
174
+ _object[_left] = _array
175
+ _object.schema = schema
176
+ _object.parent = parent
177
+ _object.fields = {}
178
+ _object.entries = setmetatable({}, {
179
+ __mode = "v",
180
+ })
181
+ local made = makeHandle(_object)
182
+ local _key_1 = key
183
+ cache[_key_1] = made
184
+ return made
185
+ end
186
+ local handleCall = function(handle, ...)
187
+ local args = { ... }
188
+ local node = nodeOf(handle)
189
+ local source = node.source
190
+ if #args > 0 then
191
+ error(if source.client then `{source.name}() is read-only on the client` else `{source.name}: read a handle with h(); write it with set or update`, 2)
192
+ end
193
+ source:beforeRead()
194
+ if node.read == nil then
195
+ local path = node.path
196
+ node.read = createComputedNode(function()
197
+ return source:read(path)
198
+ end)
199
+ end
200
+ return readComputed(node.read)
201
+ end
202
+ local handleIndex = function(handle, key)
203
+ local node = nodeOf(handle)
204
+ local _key = key
205
+ local _condition = type(_key) == "string"
206
+ if _condition then
207
+ local _key_1 = key
208
+ _condition = RESERVED[_key_1] ~= nil
209
+ if _condition then
210
+ _condition = not node.source.client
211
+ end
212
+ end
213
+ if _condition then
214
+ local _key_1 = key
215
+ return METHODS[_key_1]
216
+ end
217
+ local _key_1 = key
218
+ local _condition_1 = not (type(_key_1) == "string")
219
+ if _condition_1 then
220
+ local _key_2 = key
221
+ _condition_1 = not (type(_key_2) == "number")
222
+ end
223
+ if _condition_1 then
224
+ error("a handle's children are reached by key or index", 2)
225
+ end
226
+ return child(handle, node, key)
227
+ end
228
+ local handleNewindex = function()
229
+ return error("a handle has no fields to assign; write with set or update", 2)
230
+ end
231
+ --* @internal Rule 122: an empty table with a metatable of its own, holding its node under a private key.
232
+ function makeHandle(node)
233
+ local meta = {
234
+ __call = handleCall,
235
+ __index = handleIndex,
236
+ __newindex = handleNewindex,
237
+ [NODE] = node,
238
+ }
239
+ return setmetatable({}, meta)
240
+ end
241
+ --* @internal A root handle over `source`, typed by the descriptor `schema` (rules 115, 124).
242
+ local function rootHandle(source, schema)
243
+ return makeHandle({
244
+ source = source,
245
+ path = {},
246
+ schema = schema,
247
+ fields = {},
248
+ entries = setmetatable({}, {
249
+ __mode = "v",
250
+ }),
251
+ })
252
+ end
253
+ return {
254
+ rootHandle = rootHandle,
255
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,458 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local _envelope = TS.import(script, script.Parent, "envelope")
4
+ local emptyEnvelope = _envelope.emptyEnvelope
5
+ local envelopeBytes = _envelope.envelopeBytes
6
+ local jsonBytes = _envelope.jsonBytes
7
+ local parseEnvelope = _envelope.parseEnvelope
8
+ local _limits = TS.import(script, script.Parent, "limits")
9
+ local INBOX_MAX_BYTES = _limits.INBOX_MAX_BYTES
10
+ local INBOX_MAX_MESSAGES = _limits.INBOX_MAX_MESSAGES
11
+ local MAX_ENVELOPE_BYTES = _limits.MAX_ENVELOPE_BYTES
12
+ local MESSAGE_ID_MAX_AGE_SECONDS = _limits.MESSAGE_ID_MAX_AGE_SECONDS
13
+ local QUARANTINE_MAX_BYTES = _limits.QUARANTINE_MAX_BYTES
14
+ local QUARANTINE_MAX_MESSAGES = _limits.QUARANTINE_MAX_MESSAGES
15
+ local SEEN_MAX_MESSAGES = _limits.SEEN_MAX_MESSAGES
16
+ local _operation_id = TS.import(script, script.Parent, "operation-id")
17
+ local ageOf = _operation_id.ageOf
18
+ local createdAt = _operation_id.createdAt
19
+ local evictable = _operation_id.evictable
20
+ --[[
21
+ *
22
+ * @internal An attempt count or a quarantine move for one item, compare-and-set on the item's generation: it applies
23
+ * only while the stored item is live with exactly `generation` (rule 72).
24
+
25
+ ]]
26
+ local function addSeen(envelope, ids)
27
+ local _array = {}
28
+ local _length = #_array
29
+ local _array_1 = envelope.seen
30
+ table.move(_array_1, 1, #_array_1, _length + 1, _array)
31
+ local seen = _array
32
+ local floor = envelope.seenFloor
33
+ for _, id in ids do
34
+ if not (table.find(seen, id) ~= nil) then
35
+ table.insert(seen, id)
36
+ end
37
+ end
38
+ while #seen > SEEN_MAX_MESSAGES do
39
+ local evicted = table.remove(seen, 1)
40
+ local _exp = floor
41
+ local _condition = createdAt(evicted)
42
+ if _condition == nil then
43
+ _condition = 0
44
+ end
45
+ floor = math.max(_exp, _condition)
46
+ end
47
+ return {
48
+ seen = seen,
49
+ seenFloor = floor,
50
+ }
51
+ end
52
+ --* @internal Each id leaves the inbox or the quarantine, wherever it is, and enters seen as its exact string (rule 72).
53
+ local function applyAcks(envelope, acks)
54
+ local _set = {}
55
+ for _, _v in acks do
56
+ _set[_v] = true
57
+ end
58
+ local gone = _set
59
+ local _object = table.clone(envelope)
60
+ setmetatable(_object, nil)
61
+ local _left = "inbox"
62
+ local _exp = envelope.inbox
63
+ -- ▼ ReadonlyArray.filter ▼
64
+ local _newValue = {}
65
+ local _callback = function(item)
66
+ local _id = item.id
67
+ return not (gone[_id] ~= nil)
68
+ end
69
+ local _length = 0
70
+ for _k, _v in _exp do
71
+ if _callback(_v, _k - 1, _exp) == true then
72
+ _length += 1
73
+ _newValue[_length] = _v
74
+ end
75
+ end
76
+ -- ▲ ReadonlyArray.filter ▲
77
+ _object[_left] = _newValue
78
+ local _left_1 = "quarantine"
79
+ local _exp_1 = envelope.quarantine
80
+ -- ▼ ReadonlyArray.filter ▼
81
+ local _newValue_1 = {}
82
+ local _callback_1 = function(item)
83
+ local _id = item.id
84
+ return not (gone[_id] ~= nil)
85
+ end
86
+ local _length_1 = 0
87
+ for _k, _v in _exp_1 do
88
+ if _callback_1(_v, _k - 1, _exp_1) == true then
89
+ _length_1 += 1
90
+ _newValue_1[_length_1] = _v
91
+ end
92
+ end
93
+ -- ▲ ReadonlyArray.filter ▲
94
+ _object[_left_1] = _newValue_1
95
+ for _k, _v in addSeen(envelope, acks) do
96
+ _object[_k] = _v
97
+ end
98
+ return _object
99
+ end
100
+ --[[
101
+ *
102
+ * @internal Rule 72's compare-and-set. A move into a full quarantine leaves the item live with its attempts updated.
103
+ * A mark whose generation no longer matches skips, and the item is untouched.
104
+
105
+ ]]
106
+ local function applyMarks(envelope, marks)
107
+ local inbox = envelope.inbox
108
+ local quarantine = envelope.quarantine
109
+ for _, mark in marks do
110
+ -- ▼ ReadonlyArray.findIndex ▼
111
+ local _callback = function(item)
112
+ return item.id == mark.id and item.generation == mark.generation
113
+ end
114
+ local _result = -1
115
+ for _i, _v in inbox do
116
+ if _callback(_v, _i - 1, inbox) == true then
117
+ _result = _i - 1
118
+ break
119
+ end
120
+ end
121
+ -- ▲ ReadonlyArray.findIndex ▲
122
+ local index = _result
123
+ if index < 0 then
124
+ continue
125
+ end
126
+ local item = inbox[index + 1]
127
+ local _object = table.clone(item)
128
+ setmetatable(_object, nil)
129
+ _object.attempts = mark.attempts
130
+ _object.generation = item.generation + 1
131
+ local marked = _object
132
+ local _array = {}
133
+ local _length = #_array
134
+ local _quarantineLength = #quarantine
135
+ table.move(quarantine, 1, _quarantineLength, _length + 1, _array)
136
+ _length += _quarantineLength
137
+ local _object_1 = table.clone(marked)
138
+ setmetatable(_object_1, nil)
139
+ _object_1.reason = mark.quarantine
140
+ _array[_length + 1] = _object_1
141
+ local moved = _array
142
+ local room = mark.quarantine ~= nil and #moved <= QUARANTINE_MAX_MESSAGES and jsonBytes(moved) <= QUARANTINE_MAX_BYTES
143
+ local _array_1 = {}
144
+ local _length_1 = #_array_1
145
+ table.move(inbox, 1, #inbox, _length_1 + 1, _array_1)
146
+ local rest = _array_1
147
+ if room then
148
+ table.remove(rest, index + 1)
149
+ quarantine = moved
150
+ else
151
+ rest[index + 1] = marked
152
+ end
153
+ inbox = rest
154
+ end
155
+ local _result
156
+ if inbox == envelope.inbox then
157
+ _result = envelope
158
+ else
159
+ local _object = table.clone(envelope)
160
+ setmetatable(_object, nil)
161
+ _object.inbox = inbox
162
+ _object.quarantine = quarantine
163
+ _result = _object
164
+ end
165
+ return _result
166
+ end
167
+ --* @internal Exact structural equality of two stored JSON values (rule 68).
168
+ local function sameValue(a, b)
169
+ local _a = a
170
+ local _condition = not (type(_a) == "table")
171
+ if not _condition then
172
+ local _b = b
173
+ _condition = not (type(_b) == "table")
174
+ end
175
+ if _condition then
176
+ return a == b
177
+ end
178
+ local count = 0
179
+ for key, value in pairs(a) do
180
+ count += 1
181
+ if not sameValue(value, b[key]) then
182
+ return false
183
+ end
184
+ end
185
+ for _element, _element_1 in pairs(b) do
186
+ local _ = { _element, _element_1 }
187
+ count -= 1
188
+ end
189
+ return count == 0
190
+ end
191
+ local function stored(current, userId, envelope)
192
+ local _array = {}
193
+ local _length = #_array
194
+ local _result = current
195
+ if _result ~= nil then
196
+ _result = _result.userIds
197
+ end
198
+ local _condition = _result
199
+ if _condition == nil then
200
+ _condition = {}
201
+ end
202
+ table.move(_condition, 1, #_condition, _length + 1, _array)
203
+ local userIds = _array
204
+ local _userId = userId
205
+ if not (table.find(userIds, _userId) ~= nil) then
206
+ local _userId_1 = userId
207
+ table.insert(userIds, _userId_1)
208
+ end
209
+ local _object = {
210
+ value = envelope,
211
+ userIds = userIds,
212
+ }
213
+ local _left = "metadata"
214
+ local _result_1 = current
215
+ if _result_1 ~= nil then
216
+ _result_1 = _result_1.metadata
217
+ end
218
+ local _condition_1 = _result_1
219
+ if _condition_1 == nil then
220
+ _condition_1 = {}
221
+ end
222
+ _object[_left] = _condition_1
223
+ return _object
224
+ end
225
+ --* @internal
226
+ --[[
227
+ *
228
+ * @internal An inbox append (rules 66 to 70). Touches only `inbox`, needs no lease and works on any stored version. An
229
+ * absent key becomes an unopened envelope.
230
+
231
+ ]]
232
+ local function append(current, userId, item, wall, record)
233
+ local _result = current
234
+ if _result ~= nil then
235
+ _result = _result.value
236
+ end
237
+ local parsed = parseEnvelope(_result, "profiles")
238
+ if parsed.kind == "unreadable" then
239
+ record(parsed)
240
+ return nil
241
+ end
242
+ local envelope = if parsed.kind == "ok" then parsed.envelope else emptyEnvelope("profiles")
243
+ local _exp = envelope.inbox
244
+ -- ▼ ReadonlyArray.find ▼
245
+ local _callback = function(other)
246
+ return other.id == item.id
247
+ end
248
+ local _result_1
249
+ for _i, _v in _exp do
250
+ if _callback(_v, _i - 1, _exp) == true then
251
+ _result_1 = _v
252
+ break
253
+ end
254
+ end
255
+ -- ▲ ReadonlyArray.find ▲
256
+ local _condition = _result_1
257
+ if _condition == nil then
258
+ local _exp_1 = envelope.quarantine
259
+ -- ▼ ReadonlyArray.find ▼
260
+ local _callback_1 = function(other)
261
+ return other.id == item.id
262
+ end
263
+ local _result_2
264
+ for _i, _v in _exp_1 do
265
+ if _callback_1(_v, _i - 1, _exp_1) == true then
266
+ _result_2 = _v
267
+ break
268
+ end
269
+ end
270
+ -- ▲ ReadonlyArray.find ▲
271
+ _condition = _result_2
272
+ end
273
+ local held = _condition
274
+ if held ~= nil then
275
+ record({
276
+ kind = if held.name == item.name and sameValue(held.payload, item.payload) then "duplicate" else "reused",
277
+ })
278
+ return nil
279
+ end
280
+ local _seen = envelope.seen
281
+ local _id = item.id
282
+ if table.find(_seen, _id) ~= nil then
283
+ record({
284
+ kind = "duplicate",
285
+ })
286
+ return nil
287
+ end
288
+ local now = wall()
289
+ if ageOf(item.id, now, MESSAGE_ID_MAX_AGE_SECONDS) ~= "fresh" or createdAt(item.id) <= envelope.seenFloor then
290
+ record({
291
+ kind = "expired",
292
+ })
293
+ return nil
294
+ end
295
+ local _array = {}
296
+ local _length = #_array
297
+ local _array_1 = envelope.inbox
298
+ local _Length = #_array_1
299
+ table.move(_array_1, 1, _Length, _length + 1, _array)
300
+ _length += _Length
301
+ _array[_length + 1] = item
302
+ local inbox = _array
303
+ if #inbox > INBOX_MAX_MESSAGES or jsonBytes(inbox) > INBOX_MAX_BYTES then
304
+ record({
305
+ kind = "full",
306
+ })
307
+ return nil
308
+ end
309
+ if #envelope.seen >= SEEN_MAX_MESSAGES and not evictable(envelope.seen[1], now) then
310
+ record({
311
+ kind = "overloaded",
312
+ })
313
+ return nil
314
+ end
315
+ local _object = table.clone(envelope)
316
+ setmetatable(_object, nil)
317
+ _object.inbox = inbox
318
+ local written = _object
319
+ if envelopeBytes(written) > MAX_ENVELOPE_BYTES then
320
+ record({
321
+ kind = "full",
322
+ })
323
+ return nil
324
+ end
325
+ record({
326
+ kind = "appended",
327
+ })
328
+ return stored(current, userId, written)
329
+ end
330
+ --* @internal
331
+ --* @internal clearQuarantined (rule 73): touches only `inbox`, `quarantine` and `seen`, with no lease.
332
+ local function clearQuarantine(current, userId, ids, action, record)
333
+ local _result = current
334
+ if _result ~= nil then
335
+ _result = _result.value
336
+ end
337
+ local parsed = parseEnvelope(_result, "profiles")
338
+ if parsed.kind == "unreadable" then
339
+ record(parsed)
340
+ return nil
341
+ end
342
+ if parsed.kind == "absent" then
343
+ record({
344
+ kind = "cleared",
345
+ changed = 0,
346
+ })
347
+ return nil
348
+ end
349
+ local envelope = parsed.envelope
350
+ local _exp = envelope.quarantine
351
+ -- ▼ ReadonlyArray.filter ▼
352
+ local _newValue = {}
353
+ local _callback = function(item)
354
+ local _ids = ids
355
+ local _id = item.id
356
+ return _ids[_id] ~= nil
357
+ end
358
+ local _length = 0
359
+ for _k, _v in _exp do
360
+ if _callback(_v, _k - 1, _exp) == true then
361
+ _length += 1
362
+ _newValue[_length] = _v
363
+ end
364
+ end
365
+ -- ▲ ReadonlyArray.filter ▲
366
+ local listed = _newValue
367
+ if #listed == 0 then
368
+ record({
369
+ kind = "cleared",
370
+ changed = 0,
371
+ })
372
+ return nil
373
+ end
374
+ local _exp_1 = envelope.quarantine
375
+ -- ▼ ReadonlyArray.filter ▼
376
+ local _newValue_1 = {}
377
+ local _callback_1 = function(item)
378
+ local _ids = ids
379
+ local _id = item.id
380
+ return not (_ids[_id] ~= nil)
381
+ end
382
+ local _length_1 = 0
383
+ for _k, _v in _exp_1 do
384
+ if _callback_1(_v, _k - 1, _exp_1) == true then
385
+ _length_1 += 1
386
+ _newValue_1[_length_1] = _v
387
+ end
388
+ end
389
+ -- ▲ ReadonlyArray.filter ▲
390
+ local quarantine = _newValue_1
391
+ local written
392
+ if action == "retry" then
393
+ local _array = {}
394
+ local _length_2 = #_array
395
+ local _array_1 = envelope.inbox
396
+ local _Length = #_array_1
397
+ table.move(_array_1, 1, _Length, _length_2 + 1, _array)
398
+ _length_2 += _Length
399
+ -- ▼ ReadonlyArray.map ▼
400
+ local _newValue_2 = table.create(#listed)
401
+ local _callback_2 = function(item)
402
+ return {
403
+ id = item.id,
404
+ name = item.name,
405
+ version = item.version,
406
+ payload = item.payload,
407
+ generation = item.generation + 1,
408
+ attempts = 0,
409
+ }
410
+ end
411
+ for _k, _v in listed do
412
+ _newValue_2[_k] = _callback_2(_v, _k - 1, listed)
413
+ end
414
+ -- ▲ ReadonlyArray.map ▲
415
+ table.move(_newValue_2, 1, #_newValue_2, _length_2 + 1, _array)
416
+ local inbox = _array
417
+ if #inbox > INBOX_MAX_MESSAGES or jsonBytes(inbox) > INBOX_MAX_BYTES then
418
+ record({
419
+ kind = "full",
420
+ })
421
+ return nil
422
+ end
423
+ local _object = table.clone(envelope)
424
+ setmetatable(_object, nil)
425
+ _object.inbox = inbox
426
+ _object.quarantine = quarantine
427
+ written = _object
428
+ else
429
+ local _object = table.clone(envelope)
430
+ setmetatable(_object, nil)
431
+ _object.quarantine = quarantine
432
+ -- ▼ ReadonlyArray.map ▼
433
+ local _newValue_2 = table.create(#listed)
434
+ local _callback_2 = function(item)
435
+ return item.id
436
+ end
437
+ for _k, _v in listed do
438
+ _newValue_2[_k] = _callback_2(_v, _k - 1, listed)
439
+ end
440
+ -- ▲ ReadonlyArray.map ▲
441
+ for _k, _v in addSeen(envelope, _newValue_2) do
442
+ _object[_k] = _v
443
+ end
444
+ written = _object
445
+ end
446
+ record({
447
+ kind = "cleared",
448
+ changed = #listed,
449
+ })
450
+ return stored(current, userId, written)
451
+ end
452
+ return {
453
+ applyAcks = applyAcks,
454
+ applyMarks = applyMarks,
455
+ sameValue = sameValue,
456
+ append = append,
457
+ clearQuarantine = clearQuarantine,
458
+ }
@@ -0,0 +1 @@
1
+ export {};