@axpecter/lync 1.3.1 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +250 -68
  2. package/package.json +1 -1
  3. package/src/Types.luau +13 -2
  4. package/src/api/Group.luau +77 -46
  5. package/src/api/Namespace.luau +13 -6
  6. package/src/api/Packet.luau +52 -30
  7. package/src/api/Query.luau +116 -90
  8. package/src/api/Scope.luau +73 -0
  9. package/src/api/Signal.luau +10 -4
  10. package/src/codec/Base.luau +7 -3
  11. package/src/codec/composite/Array.luau +18 -15
  12. package/src/codec/composite/Map.luau +45 -31
  13. package/src/codec/composite/Optional.luau +3 -2
  14. package/src/codec/composite/Shared.luau +7 -5
  15. package/src/codec/composite/Struct.luau +6 -4
  16. package/src/codec/composite/Tagged.luau +6 -6
  17. package/src/codec/composite/Tuple.luau +9 -7
  18. package/src/codec/datatype/Buffer.luau +3 -2
  19. package/src/codec/datatype/CFrame.luau +2 -1
  20. package/src/codec/datatype/Instance.luau +3 -2
  21. package/src/codec/datatype/Sequence.luau +3 -4
  22. package/src/codec/datatype/String.luau +3 -6
  23. package/src/codec/meta/Auto.luau +77 -72
  24. package/src/codec/meta/Bitfield.luau +5 -4
  25. package/src/codec/meta/Enum.luau +6 -5
  26. package/src/codec/meta/Quantized.luau +5 -4
  27. package/src/codec/meta/Unknown.luau +5 -1
  28. package/src/codec/primitive/Float16.luau +5 -4
  29. package/src/codec/primitive/Varint.luau +2 -2
  30. package/src/index.d.ts +65 -26
  31. package/src/init.luau +60 -42
  32. package/src/internal/Baseline.luau +6 -2
  33. package/src/internal/Channel.luau +11 -6
  34. package/src/internal/Middleware.luau +18 -8
  35. package/src/internal/Pool.luau +5 -5
  36. package/src/internal/Registry.luau +4 -4
  37. package/src/transport/Bridge.luau +4 -3
  38. package/src/transport/Client.luau +4 -3
  39. package/src/transport/Gate.luau +5 -5
  40. package/src/transport/Reader.luau +3 -3
  41. package/src/transport/Server.luau +14 -16
@@ -4,14 +4,15 @@
4
4
 
5
5
  local Baseline = require (script.Parent.Parent.Parent.internal.Baseline)
6
6
  local Channel = require (script.Parent.Parent.Parent.internal.Channel)
7
- local alloc = Channel.alloc
8
7
  local Shared = require (script.Parent.Shared)
9
8
  local Types = require (script.Parent.Parent.Parent.Types)
9
+ local Varint = require (script.Parent.Parent.primitive.Varint)
10
10
 
11
11
  type ChannelState = Types.ChannelState
12
12
  type Codec<T> = Types.Codec<T>
13
- local Varint = require (script.Parent.Parent.primitive.Varint)
13
+ type InternalCodec<T> = Types.InternalCodec<T>
14
14
 
15
+ local alloc = Channel.alloc
15
16
  local rangeEqual = Shared.rangeEqual
16
17
  local acquireScratch = Shared.acquireScratch
17
18
  local releaseScratch = Shared.releaseScratch
@@ -20,7 +21,7 @@ local FLAG_DELTA = Shared.FLAG_DELTA
20
21
  local FLAG_FULL = Shared.FLAG_FULL
21
22
  local FLAG_UNCHANGED = Shared.FLAG_UNCHANGED
22
23
 
23
- -- Public -----------------------------------------------------------------
24
+ -- Public -------------------------------------------------------------
24
25
 
25
26
  local Array = {}
26
27
 
@@ -30,9 +31,10 @@ function Array.deltaArray (element: Codec<any>, maxCount: number?): Codec<{ any
30
31
  local writeElement = element.write
31
32
  local readElement = element.read
32
33
 
33
- local elemSize = (element :: any)._size :: number?
34
- local elemDirect = (element :: any)._directWrite
35
- local elemDRead = (element :: any)._directRead
34
+ local internal = element :: InternalCodec<any>
35
+ local elemSize = internal._size
36
+ local elemWrite = internal._directWrite
37
+ local elemRead = internal._directRead
36
38
 
37
39
  return table.freeze ({
38
40
  _isDelta = true,
@@ -45,13 +47,13 @@ function Array.deltaArray (element: Codec<any>, maxCount: number?): Codec<{ any
45
47
  local bounds = table.create (len + 1)
46
48
  bounds[1] = 0
47
49
 
48
- if elemDirect and elemSize then
50
+ if elemWrite and elemSize then
49
51
  local totalBytes = len * elemSize
50
52
  alloc (scratch, totalBytes)
51
53
  local b = scratch.buff
52
54
  local c = 0
53
55
  for i = 1, len do
54
- elemDirect (b, c, value[i])
56
+ elemWrite (b, c, value[i])
55
57
  c += elemSize
56
58
  bounds[i + 1] = c
57
59
  end
@@ -147,9 +149,9 @@ function Array.deltaArray (element: Codec<any>, maxCount: number?): Codec<{ any
147
149
 
148
150
  local result = table.create (len)
149
151
 
150
- if elemDRead and elemSize then
152
+ if elemRead and elemSize then
151
153
  for i = 1, len do
152
- result[i] = elemDRead (src, absPos)
154
+ result[i] = elemRead (src, absPos)
153
155
  absPos += elemSize
154
156
  end
155
157
  else
@@ -174,8 +176,8 @@ function Array.deltaArray (element: Codec<any>, maxCount: number?): Codec<{ any
174
176
  local idx, idxBytes = Varint.read (src, absPos)
175
177
  absPos += idxBytes
176
178
 
177
- if elemDRead and elemSize then
178
- result[idx + 1] = elemDRead (src, absPos)
179
+ if elemRead and elemSize then
180
+ result[idx + 1] = elemRead (src, absPos)
179
181
  absPos += elemSize
180
182
  else
181
183
  local val, n = readElement (src, absPos, refs)
@@ -191,9 +193,10 @@ function Array.deltaArray (element: Codec<any>, maxCount: number?): Codec<{ any
191
193
  end
192
194
 
193
195
  function Array.array (element: Codec<any>, maxCount: number?): Codec<{ any }>
194
- local elementSize = (element :: any)._size :: number?
195
- local directWrite = (element :: any)._directWrite
196
- local directRead = (element :: any)._directRead
196
+ local internal = element :: InternalCodec<any>
197
+ local elementSize = internal._size
198
+ local directWrite = internal._directWrite
199
+ local directRead = internal._directRead
197
200
 
198
201
  if elementSize and directWrite and directRead then
199
202
  return table.freeze ({
@@ -4,14 +4,15 @@
4
4
 
5
5
  local Baseline = require (script.Parent.Parent.Parent.internal.Baseline)
6
6
  local Channel = require (script.Parent.Parent.Parent.internal.Channel)
7
- local alloc = Channel.alloc
8
7
  local Shared = require (script.Parent.Shared)
9
8
  local Types = require (script.Parent.Parent.Parent.Types)
9
+ local Varint = require (script.Parent.Parent.primitive.Varint)
10
10
 
11
11
  type ChannelState = Types.ChannelState
12
12
  type Codec<T> = Types.Codec<T>
13
- local Varint = require (script.Parent.Parent.primitive.Varint)
13
+ type InternalCodec<T> = Types.InternalCodec<T>
14
14
 
15
+ local alloc = Channel.alloc
15
16
  local rangeEqual = Shared.rangeEqual
16
17
  local acquireScratch = Shared.acquireScratch
17
18
  local releaseScratch = Shared.releaseScratch
@@ -20,7 +21,7 @@ local FLAG_DELTA = Shared.FLAG_DELTA
20
21
  local FLAG_FULL = Shared.FLAG_FULL
21
22
  local FLAG_UNCHANGED = Shared.FLAG_UNCHANGED
22
23
 
23
- -- Public -----------------------------------------------------------------
24
+ -- Public -------------------------------------------------------------
24
25
 
25
26
  local Map = {}
26
27
 
@@ -29,12 +30,15 @@ function Map.map (
29
30
  valueCodec: Codec<any>,
30
31
  maxCount: number?
31
32
  ): Codec<{ [any]: any }>
32
- local keySize = (keyCodec :: any)._size :: number?
33
- local valSize = (valueCodec :: any)._size :: number?
34
- local keyDWrite = (keyCodec :: any)._directWrite
35
- local valDWrite = (valueCodec :: any)._directWrite
36
- local keyDRead = (keyCodec :: any)._directRead
37
- local valDRead = (valueCodec :: any)._directRead
33
+ local keyInternal = keyCodec :: InternalCodec<any>
34
+ local valInternal = valueCodec :: InternalCodec<any>
35
+
36
+ local keySize = keyInternal._size
37
+ local valSize = valInternal._size
38
+ local keyDWrite = keyInternal._directWrite
39
+ local valDWrite = valInternal._directWrite
40
+ local keyDRead = keyInternal._directRead
41
+ local valDRead = valInternal._directRead
38
42
 
39
43
  if keySize and valSize and keyDWrite and valDWrite and keyDRead and valDRead then
40
44
  local entrySize = keySize + valSize
@@ -132,12 +136,14 @@ function Map.map (
132
136
  })
133
137
  end
134
138
 
135
- -- Delta map: tracks per-key changes. First frame is full, then upserts + removes only.
136
- --
137
- -- Wire format:
138
- -- FLAG_FULL: u8(1) + varint(count) + [key+value ...]
139
- -- FLAG_UNCHANGED: u8(2)
140
- -- FLAG_DELTA: u8(0) + varint(upsertN) + [key+value ...] + varint(removeN) + [key ...]
139
+ --[[
140
+ Delta map: tracks per-key changes. First frame is full, then upserts + removes only.
141
+
142
+ Wire format:
143
+ FLAG_FULL: u8(1) + varint(count) + [key+value ...]
144
+ FLAG_UNCHANGED: u8(2)
145
+ FLAG_DELTA: u8(0) + varint(upsertN) + [key+value ...] + varint(removeN) + [key ...]
146
+ ]]
141
147
  function Map.deltaMap (
142
148
  keyCodec: Codec<any>,
143
149
  valueCodec: Codec<any>,
@@ -150,23 +156,39 @@ function Map.deltaMap (
150
156
  local readKey = keyCodec.read
151
157
  local readVal = valueCodec.read
152
158
 
153
- local keySize = (keyCodec :: any)._size :: number?
154
- local valSize = (valueCodec :: any)._size :: number?
155
- local keyDWrite = (keyCodec :: any)._directWrite
156
- local valDWrite = (valueCodec :: any)._directWrite
157
- local keyDRead = (keyCodec :: any)._directRead
158
- local valDRead = (valueCodec :: any)._directRead
159
+ local keyInternal = keyCodec :: InternalCodec<any>
160
+ local valInternal = valueCodec :: InternalCodec<any>
161
+
162
+ local keySize = keyInternal._size
163
+ local valSize = valInternal._size
164
+ local keyDWrite = keyInternal._directWrite
165
+ local valDWrite = valInternal._directWrite
166
+ local keyDRead = keyInternal._directRead
167
+ local valDRead = valInternal._directRead
168
+
159
169
  local scratchDirect = keySize and valSize and keyDWrite and valDWrite
160
170
  local entrySize = if keySize and valSize then keySize + valSize else nil
161
171
 
172
+ type EntryBounds = {
173
+ keyOff: number,
174
+ keyLen: number,
175
+ valOff: number,
176
+ valLen: number,
177
+ }
178
+
179
+ type DeltaMapCache = {
180
+ raw: buffer,
181
+ entries: { EntryBounds },
182
+ keyLookup: { [string]: number },
183
+ count: number,
184
+ }
185
+
162
186
  return table.freeze ({
163
187
  _isDelta = true,
164
188
 
165
189
  write = function (ch: ChannelState, value: { [any]: any }): ()
166
190
  local scratch = acquireScratch ()
167
191
 
168
- type EntryBounds = { keyOff: number, keyLen: number, valOff: number, valLen: number }
169
-
170
192
  local entries = {} :: { EntryBounds }
171
193
  local keyLookup = {} :: { [string]: number }
172
194
  local entryCount = 0
@@ -213,14 +235,6 @@ function Map.deltaMap (
213
235
  end
214
236
 
215
237
  local scratchTotal = scratch.cursor
216
-
217
- type DeltaMapCache = {
218
- raw: buffer,
219
- entries: { EntryBounds },
220
- keyLookup: { [string]: number },
221
- count: number,
222
- }
223
-
224
238
  local cache = ch.deltas[deltaId] :: DeltaMapCache?
225
239
 
226
240
  if not cache then
@@ -3,13 +3,14 @@
3
3
  -- Optional codec. 1 byte flag, value only if present.
4
4
 
5
5
  local Channel = require (script.Parent.Parent.Parent.internal.Channel)
6
- local alloc = Channel.alloc
7
6
  local Types = require (script.Parent.Parent.Parent.Types)
8
7
 
9
8
  type ChannelState = Types.ChannelState
10
9
  type Codec<T> = Types.Codec<T>
11
10
 
12
- -- Public -----------------------------------------------------------------
11
+ local alloc = Channel.alloc
12
+
13
+ -- Public -------------------------------------------------------------
13
14
 
14
15
  local Optional = {}
15
16
 
@@ -3,11 +3,13 @@
3
3
  -- Shared helpers for composite codecs: delta flags, scratch pool, struct field extraction, bool packing.
4
4
 
5
5
  local Channel = require (script.Parent.Parent.Parent.internal.Channel)
6
- local alloc = Channel.alloc
6
+ local Types = require (script.Parent.Parent.Parent.Types)
7
+
8
+ type ChannelState = Types.ChannelState
7
9
 
8
- type ChannelState = any
10
+ local alloc = Channel.alloc
9
11
 
10
- -- Constants --------------------------------------------------------------
12
+ -- Constants ----------------------------------------------------------
11
13
 
12
14
  local band = bit32.band
13
15
  local bor = bit32.bor
@@ -19,13 +21,13 @@ local FLAG_DELTA = 0
19
21
  local FLAG_FULL = 1
20
22
  local FLAG_UNCHANGED = 2
21
23
 
22
- -- State ------------------------------------------------------------------
24
+ -- State --------------------------------------------------------------
23
25
 
24
26
  local _nextDeltaId = 1
25
27
  local _scratchStack = {} :: { ChannelState }
26
28
  local _scratchDepth = 0
27
29
 
28
- -- Public -----------------------------------------------------------------
30
+ -- Public -------------------------------------------------------------
29
31
 
30
32
  local Shared = {
31
33
  FLAG_DELTA = FLAG_DELTA,
@@ -4,13 +4,14 @@
4
4
 
5
5
  local Baseline = require (script.Parent.Parent.Parent.internal.Baseline)
6
6
  local Channel = require (script.Parent.Parent.Parent.internal.Channel)
7
- local alloc = Channel.alloc
8
7
  local Shared = require (script.Parent.Shared)
9
8
  local Types = require (script.Parent.Parent.Parent.Types)
10
9
 
11
10
  type ChannelState = Types.ChannelState
12
11
  type Codec<T> = Types.Codec<T>
12
+ type InternalCodec<T> = Types.InternalCodec<T>
13
13
 
14
+ local alloc = Channel.alloc
14
15
  local extractFields = Shared.extractFields
15
16
  local packBools = Shared.packBools
16
17
  local unpackBools = Shared.unpackBools
@@ -34,7 +35,7 @@ type DeltaCache = {
34
35
  total: number,
35
36
  }
36
37
 
37
- -- Public -----------------------------------------------------------------
38
+ -- Public -------------------------------------------------------------
38
39
 
39
40
  local Struct = {}
40
41
 
@@ -55,7 +56,7 @@ function Struct.struct (schema: { [string]: Codec<any> }): Codec<any>
55
56
  local fieldSizes = table.create (dataCount) :: { number }
56
57
 
57
58
  for i = 1, dataCount do
58
- local codec = dataCodecs[i] :: any
59
+ local codec = dataCodecs[i] :: InternalCodec<any>
59
60
  local size = codec._size
60
61
  local dw = codec._directWrite
61
62
  local dr = codec._directRead
@@ -183,6 +184,7 @@ function Struct.struct (schema: { [string]: Codec<any> }): Codec<any>
183
184
  end,
184
185
  })
185
186
  end
187
+
186
188
  function Struct.deltaStruct (schema: { [string]: Codec<any> }): Codec<any>
187
189
  local dataKeys, dataCodecs, boolKeys = extractFields (schema)
188
190
 
@@ -213,7 +215,7 @@ function Struct.deltaStruct (schema: { [string]: Codec<any> }): Codec<any>
213
215
  local scratchDataTotal = 0
214
216
 
215
217
  for i = 1, dataCount do
216
- local codec = dataCodecs[i] :: any
218
+ local codec = dataCodecs[i] :: InternalCodec<any>
217
219
  local size = codec._size
218
220
  local dw = codec._directWrite
219
221
  if size and dw then
@@ -3,13 +3,15 @@
3
3
  -- Discriminated union codec. u8 variant tag + variant payload.
4
4
 
5
5
  local Channel = require (script.Parent.Parent.Parent.internal.Channel)
6
- local alloc = Channel.alloc
7
6
  local Types = require (script.Parent.Parent.Parent.Types)
8
7
 
9
8
  type ChannelState = Types.ChannelState
10
9
  type Codec<T> = Types.Codec<T>
10
+ type InternalCodec<T> = Types.InternalCodec<T>
11
+
12
+ local alloc = Channel.alloc
11
13
 
12
- -- Public -----------------------------------------------------------------
14
+ -- Public -------------------------------------------------------------
13
15
 
14
16
  local Tagged = {}
15
17
 
@@ -42,12 +44,12 @@ function Tagged.define (tagField: string, variants: { [string]: Codec<any> }): C
42
44
  local tagSizes = table.create (count) :: { number? }
43
45
 
44
46
  local allDirect = true
45
- local uniformSize: number? = (variants[names[1]] :: any)._size
47
+ local uniformSize: number? = (variants[names[1]] :: InternalCodec<any>)._size
46
48
  local directWrites = table.create (count) :: { any }
47
49
  local directReads = table.create (count) :: { any }
48
50
 
49
51
  for i, name in names do
50
- local codec = variants[name] :: any
52
+ local codec = variants[name] :: InternalCodec<any>
51
53
  nameToTag[name] = i
52
54
  tagCodecs[i] = codec
53
55
  tagNames[i] = name
@@ -82,8 +84,6 @@ function Tagged.define (tagField: string, variants: { [string]: Codec<any> }): C
82
84
 
83
85
  -- If uniform size, expose _directWrite/_directRead for parent struct/array
84
86
  if fixedSize then
85
- local variantBytes = uniformSize :: number
86
-
87
87
  return table.freeze ({
88
88
  _size = fixedSize,
89
89
  _directWrite = function (b: buffer, offset: number, value: any): ()
@@ -3,13 +3,15 @@
3
3
  -- Positional ordered codec. Like struct but indexed, not keyed.
4
4
 
5
5
  local Channel = require (script.Parent.Parent.Parent.internal.Channel)
6
- local alloc = Channel.alloc
7
6
  local Types = require (script.Parent.Parent.Parent.Types)
8
7
 
9
8
  type ChannelState = Types.ChannelState
10
9
  type Codec<T> = Types.Codec<T>
10
+ type InternalCodec<T> = Types.InternalCodec<T>
11
+
12
+ local alloc = Channel.alloc
11
13
 
12
- -- Public -----------------------------------------------------------------
14
+ -- Public -------------------------------------------------------------
13
15
 
14
16
  local Tuple = {}
15
17
 
@@ -29,10 +31,10 @@ function Tuple.define (...: Codec<any>): Codec<{ any }>
29
31
  local fieldSizes = table.create (count) :: { number }
30
32
 
31
33
  for i = 1, count do
32
- local codec = codecs[i] :: any
33
- local size = codec._size
34
- local dw = codec._directWrite
35
- local dr = codec._directRead
34
+ local internal = codecs[i] :: InternalCodec<any>
35
+ local size = internal._size
36
+ local dw = internal._directWrite
37
+ local dr = internal._directRead
36
38
 
37
39
  if size and dw and dr then
38
40
  fieldSizes[i] = size
@@ -54,7 +56,7 @@ function Tuple.define (...: Codec<any>): Codec<{ any }>
54
56
  if not canDirect then
55
57
  totalSize = 0 :: any
56
58
  for i = 1, count do
57
- local size = (codecs[i] :: any)._size
59
+ local size = (codecs[i] :: InternalCodec<any>)._size
58
60
  if size then
59
61
  totalSize = (totalSize :: number) + size
60
62
  else
@@ -3,13 +3,14 @@
3
3
  -- Raw buffer codec with varint length prefix.
4
4
 
5
5
  local Channel = require (script.Parent.Parent.Parent.internal.Channel)
6
- local alloc = Channel.alloc
7
6
  local Types = require (script.Parent.Parent.Parent.Types)
8
7
  local Varint = require (script.Parent.Parent.primitive.Varint)
9
8
 
10
9
  type ChannelState = Types.ChannelState
11
10
 
12
- -- Public -----------------------------------------------------------------
11
+ local alloc = Channel.alloc
12
+
13
+ -- Public -------------------------------------------------------------
13
14
 
14
15
  local Buffer = {}
15
16
 
@@ -4,9 +4,10 @@
4
4
 
5
5
  local Base = require (script.Parent.Parent.Base)
6
6
 
7
+ local sqrt = math.sqrt
8
+
7
9
  -- f32 machine epsilon * 2 to absorb round-trip noise.
8
10
  local EPSILON = 2.4e-7
9
- local sqrt = math.sqrt
10
11
 
11
12
  local function writeCFrame (b: buffer, c: number, value: CFrame): ()
12
13
  local position = value.Position
@@ -3,12 +3,13 @@
3
3
  -- Instance codec via sidecar reference array.
4
4
 
5
5
  local Channel = require (script.Parent.Parent.Parent.internal.Channel)
6
- local alloc = Channel.alloc
7
6
  local Types = require (script.Parent.Parent.Parent.Types)
8
7
 
9
8
  type ChannelState = Types.ChannelState
10
9
 
11
- -- Public -----------------------------------------------------------------
10
+ local alloc = Channel.alloc
11
+
12
+ -- Public -------------------------------------------------------------
12
13
 
13
14
  local InstanceCodec = {}
14
15
 
@@ -3,15 +3,14 @@
3
3
  -- NumberSequence and ColorSequence codecs with varint length prefix.
4
4
 
5
5
  local Channel = require (script.Parent.Parent.Parent.internal.Channel)
6
- local alloc = Channel.alloc
7
6
  local Types = require (script.Parent.Parent.Parent.Types)
8
7
  local Varint = require (script.Parent.Parent.primitive.Varint)
9
8
 
10
9
  type ChannelState = Types.ChannelState
11
10
 
12
- type ChannelState = Types.ChannelState
11
+ local alloc = Channel.alloc
13
12
 
14
- -- Constants --------------------------------------------------------------
13
+ -- Constants ----------------------------------------------------------
15
14
 
16
15
  local NS_STRIDE = 12
17
16
  local CS_STRIDE = 7
@@ -19,7 +18,7 @@ local CS_STRIDE = 7
19
18
  local round = math.round
20
19
  local clamp = math.clamp
21
20
 
22
- -- Public -----------------------------------------------------------------
21
+ -- Public -------------------------------------------------------------
23
22
 
24
23
  local Sequence = {}
25
24
 
@@ -3,17 +3,14 @@
3
3
  -- Variable-length string codec with varint length prefix.
4
4
 
5
5
  local Channel = require (script.Parent.Parent.Parent.internal.Channel)
6
- local alloc = Channel.alloc
7
6
  local Types = require (script.Parent.Parent.Parent.Types)
8
7
  local Varint = require (script.Parent.Parent.primitive.Varint)
9
8
 
10
9
  type ChannelState = Types.ChannelState
11
10
 
12
- -- Constants --------------------------------------------------------------
13
-
14
- local floor = math.floor
11
+ local alloc = Channel.alloc
15
12
 
16
- -- Public -----------------------------------------------------------------
13
+ -- Public -------------------------------------------------------------
17
14
 
18
15
  local String = {}
19
16
 
@@ -59,7 +56,7 @@ String.string = table.freeze ({
59
56
  })
60
57
 
61
58
  function String.bounded (maxLength: number): any
62
- if maxLength <= 0 or maxLength ~= floor (maxLength) then
59
+ if maxLength <= 0 or maxLength ~= math.floor (maxLength) then
63
60
  error (`[Lync] boundedString maxLength must be a positive integer, got {maxLength}`)
64
61
  end
65
62