dredless 0.2.0 → 0.2.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 (77) hide show
  1. package/README.md +48 -48
  2. package/docs/API_REFERENCE.md +2481 -2481
  3. package/docs/BROWSER_API.md +98 -98
  4. package/docs/NODE_API.md +359 -359
  5. package/package.json +34 -34
  6. package/src/browser.d.ts +212 -212
  7. package/src/browser.js +133 -133
  8. package/src/client/core.js +1202 -1202
  9. package/src/client/domains/index.js +1818 -1818
  10. package/src/client/index.d.ts +2 -2
  11. package/src/client/index.js +1 -1
  12. package/src/compression/lz4.d.ts +1 -1
  13. package/src/compression/lz4.js +112 -112
  14. package/src/constants.js +74 -74
  15. package/src/crypto/chacha-native.d.ts +9 -9
  16. package/src/crypto/chacha-native.js +48 -48
  17. package/src/crypto/chacha.d.ts +25 -25
  18. package/src/crypto/chacha.js +274 -274
  19. package/src/events.js +39 -39
  20. package/src/index.d.ts +2277 -2277
  21. package/src/index.js +125 -125
  22. package/src/network/browser-session.js +291 -291
  23. package/src/network/connection.d.ts +1 -1
  24. package/src/network/connection.js +31 -31
  25. package/src/network/cookies.js +85 -85
  26. package/src/network/http.js +34 -34
  27. package/src/network/index.d.ts +4 -4
  28. package/src/network/index.js +4 -4
  29. package/src/network/servers.d.ts +7 -7
  30. package/src/network/servers.js +133 -133
  31. package/src/network/session.d.ts +7 -7
  32. package/src/network/session.js +320 -320
  33. package/src/network/ships.d.ts +12 -12
  34. package/src/network/ships.js +73 -73
  35. package/src/node.d.ts +2 -2
  36. package/src/node.js +8 -8
  37. package/src/protocol/codec/binary.d.ts +3 -3
  38. package/src/protocol/codec/binary.js +52 -52
  39. package/src/protocol/codec/msgpack.d.ts +3 -3
  40. package/src/protocol/codec/msgpack.js +555 -555
  41. package/src/protocol/inbound/frame.d.ts +1 -1
  42. package/src/protocol/inbound/frame.js +8 -8
  43. package/src/protocol/inbound/world-payload.d.ts +3 -3
  44. package/src/protocol/inbound/world-payload.js +21 -21
  45. package/src/protocol/index.d.ts +11 -11
  46. package/src/protocol/index.js +19 -19
  47. package/src/protocol/outbound/blueprint.d.ts +22 -22
  48. package/src/protocol/outbound/blueprint.js +36 -36
  49. package/src/protocol/outbound/commands.d.ts +3 -3
  50. package/src/protocol/outbound/commands.js +149 -149
  51. package/src/protocol/outbound/comms.d.ts +28 -28
  52. package/src/protocol/outbound/comms.js +40 -40
  53. package/src/protocol/outbound/inventory.d.ts +64 -64
  54. package/src/protocol/outbound/inventory.js +147 -147
  55. package/src/protocol/outbound/ship-management.d.ts +84 -84
  56. package/src/protocol/outbound/ship-management.js +221 -221
  57. package/src/protocol/outbound/sign.d.ts +18 -18
  58. package/src/protocol/outbound/sign.js +45 -45
  59. package/src/protocol/outbound/ui-config.d.ts +157 -157
  60. package/src/protocol/outbound/ui-config.js +578 -578
  61. package/src/runtime.js +36 -36
  62. package/src/state/generator-maze.d.ts +32 -32
  63. package/src/state/generator-maze.js +370 -370
  64. package/src/state/index.d.ts +3 -3
  65. package/src/state/index.js +3 -3
  66. package/src/state/items.js +20 -20
  67. package/src/state/model/decoder.js +1554 -1554
  68. package/src/state/model/index.d.ts +33 -33
  69. package/src/state/model/index.js +2 -2
  70. package/src/state/model/loader-config.js +1020 -1020
  71. package/src/state/model/reader.js +69 -69
  72. package/src/state/model/state.js +1257 -1257
  73. package/src/state/overworld.js +72 -72
  74. package/src/state/tilesets.js +53 -53
  75. package/src/state/world/index.d.ts +29 -29
  76. package/src/state/world/index.js +180 -180
  77. package/src/state/world/state.js +297 -297
@@ -1,274 +1,274 @@
1
- import {encoder, SHARED_CHACHA_MATERIAL} from "../constants.js";
2
- import {toUint8Array} from "../protocol/codec/binary.js";
3
-
4
- function rotl32(x, n) {
5
- n &= 31;
6
- return ((x << n) | (x >>> (32 - n))) >>> 0;
7
- }
8
-
9
- function rotr32(x, n) {
10
- n &= 31;
11
- return ((x >>> n) | (x << (32 - n))) >>> 0;
12
- }
13
-
14
- function quarterRound(state, a, b, c, d) {
15
- state[a] = (state[a] + state[b]) >>> 0;
16
- state[d] ^= state[a];
17
- state[d] = rotl32(state[d], 16);
18
- state[c] = (state[c] + state[d]) >>> 0;
19
- state[b] ^= state[c];
20
- state[b] = rotl32(state[b], 12);
21
- state[a] = (state[a] + state[b]) >>> 0;
22
- state[d] ^= state[a];
23
- state[d] = rotl32(state[d], 8);
24
- state[c] = (state[c] + state[d]) >>> 0;
25
- state[b] ^= state[c];
26
- state[b] = rotl32(state[b], 7);
27
- }
28
-
29
- // Optional native backend. Node's OpenSSL exposes a raw `chacha20` stream cipher
30
- // whose keystream is identical to this implementation, and it is ~27x faster on
31
- // large payloads. It is installed by src/node.js rather than imported here so
32
- // that browser bundles never see a `node:crypto` specifier.
33
- let nativeBlockCipher = null;
34
-
35
- function installNativeChaCha20(cipherFactory) {
36
- nativeBlockCipher = typeof cipherFactory === "function" ? cipherFactory : null;
37
- }
38
-
39
- // Native call overhead dominates below roughly this size; measured crossover is
40
- // near 150 bytes, so stay in JS for the small per-tick payloads.
41
- const NATIVE_MIN_BYTES = 256;
42
-
43
- // Reused across blocks: the keystream words for one 64-byte block. Safe because
44
- // generation is synchronous and single-threaded.
45
- const SCRATCH_BLOCK = new Uint32Array(16);
46
-
47
- function readLe32(bytes, offset) {
48
- return (bytes[offset] | (bytes[offset + 1] << 8) | (bytes[offset + 2] << 16) | (bytes[offset + 3] << 24)) >>> 0;
49
- }
50
-
51
- // Writes `length` keystream bytes into `out` starting at 0, XORing against
52
- // `source` when supplied. Keeping generation and XOR in one pass avoids
53
- // allocating a full second buffer for the keystream.
54
- function chacha20Into(out, key, nonce, length, source) {
55
- const k0 = readLe32(key, 0), k1 = readLe32(key, 4), k2 = readLe32(key, 8), k3 = readLe32(key, 12);
56
- const k4 = readLe32(key, 16), k5 = readLe32(key, 20), k6 = readLe32(key, 24), k7 = readLe32(key, 28);
57
- const n0 = readLe32(nonce, 0), n1 = readLe32(nonce, 4), n2 = readLe32(nonce, 8);
58
-
59
- let counter = 0;
60
- let offset = 0;
61
- const block = SCRATCH_BLOCK;
62
-
63
- while (offset < length) {
64
- let x0 = 0x61707865, x1 = 0x3320646e, x2 = 0x79622d32, x3 = 0x6b206574;
65
- let x4 = k0, x5 = k1, x6 = k2, x7 = k3;
66
- let x8 = k4, x9 = k5, x10 = k6, x11 = k7;
67
- let x12 = counter, x13 = n0, x14 = n1, x15 = n2;
68
-
69
- for (let i = 0; i < 10; i++) {
70
- // column rounds
71
- x0 = (x0 + x4) >>> 0;
72
- x12 ^= x0;
73
- x12 = (x12 << 16) | (x12 >>> 16);
74
- x8 = (x8 + x12) >>> 0;
75
- x4 ^= x8;
76
- x4 = (x4 << 12) | (x4 >>> 20);
77
- x0 = (x0 + x4) >>> 0;
78
- x12 ^= x0;
79
- x12 = (x12 << 8) | (x12 >>> 24);
80
- x8 = (x8 + x12) >>> 0;
81
- x4 ^= x8;
82
- x4 = (x4 << 7) | (x4 >>> 25);
83
-
84
- x1 = (x1 + x5) >>> 0;
85
- x13 ^= x1;
86
- x13 = (x13 << 16) | (x13 >>> 16);
87
- x9 = (x9 + x13) >>> 0;
88
- x5 ^= x9;
89
- x5 = (x5 << 12) | (x5 >>> 20);
90
- x1 = (x1 + x5) >>> 0;
91
- x13 ^= x1;
92
- x13 = (x13 << 8) | (x13 >>> 24);
93
- x9 = (x9 + x13) >>> 0;
94
- x5 ^= x9;
95
- x5 = (x5 << 7) | (x5 >>> 25);
96
-
97
- x2 = (x2 + x6) >>> 0;
98
- x14 ^= x2;
99
- x14 = (x14 << 16) | (x14 >>> 16);
100
- x10 = (x10 + x14) >>> 0;
101
- x6 ^= x10;
102
- x6 = (x6 << 12) | (x6 >>> 20);
103
- x2 = (x2 + x6) >>> 0;
104
- x14 ^= x2;
105
- x14 = (x14 << 8) | (x14 >>> 24);
106
- x10 = (x10 + x14) >>> 0;
107
- x6 ^= x10;
108
- x6 = (x6 << 7) | (x6 >>> 25);
109
-
110
- x3 = (x3 + x7) >>> 0;
111
- x15 ^= x3;
112
- x15 = (x15 << 16) | (x15 >>> 16);
113
- x11 = (x11 + x15) >>> 0;
114
- x7 ^= x11;
115
- x7 = (x7 << 12) | (x7 >>> 20);
116
- x3 = (x3 + x7) >>> 0;
117
- x15 ^= x3;
118
- x15 = (x15 << 8) | (x15 >>> 24);
119
- x11 = (x11 + x15) >>> 0;
120
- x7 ^= x11;
121
- x7 = (x7 << 7) | (x7 >>> 25);
122
-
123
- // diagonal rounds
124
- x0 = (x0 + x5) >>> 0;
125
- x15 ^= x0;
126
- x15 = (x15 << 16) | (x15 >>> 16);
127
- x10 = (x10 + x15) >>> 0;
128
- x5 ^= x10;
129
- x5 = (x5 << 12) | (x5 >>> 20);
130
- x0 = (x0 + x5) >>> 0;
131
- x15 ^= x0;
132
- x15 = (x15 << 8) | (x15 >>> 24);
133
- x10 = (x10 + x15) >>> 0;
134
- x5 ^= x10;
135
- x5 = (x5 << 7) | (x5 >>> 25);
136
-
137
- x1 = (x1 + x6) >>> 0;
138
- x12 ^= x1;
139
- x12 = (x12 << 16) | (x12 >>> 16);
140
- x11 = (x11 + x12) >>> 0;
141
- x6 ^= x11;
142
- x6 = (x6 << 12) | (x6 >>> 20);
143
- x1 = (x1 + x6) >>> 0;
144
- x12 ^= x1;
145
- x12 = (x12 << 8) | (x12 >>> 24);
146
- x11 = (x11 + x12) >>> 0;
147
- x6 ^= x11;
148
- x6 = (x6 << 7) | (x6 >>> 25);
149
-
150
- x2 = (x2 + x7) >>> 0;
151
- x13 ^= x2;
152
- x13 = (x13 << 16) | (x13 >>> 16);
153
- x8 = (x8 + x13) >>> 0;
154
- x7 ^= x8;
155
- x7 = (x7 << 12) | (x7 >>> 20);
156
- x2 = (x2 + x7) >>> 0;
157
- x13 ^= x2;
158
- x13 = (x13 << 8) | (x13 >>> 24);
159
- x8 = (x8 + x13) >>> 0;
160
- x7 ^= x8;
161
- x7 = (x7 << 7) | (x7 >>> 25);
162
-
163
- x3 = (x3 + x4) >>> 0;
164
- x14 ^= x3;
165
- x14 = (x14 << 16) | (x14 >>> 16);
166
- x9 = (x9 + x14) >>> 0;
167
- x4 ^= x9;
168
- x4 = (x4 << 12) | (x4 >>> 20);
169
- x3 = (x3 + x4) >>> 0;
170
- x14 ^= x3;
171
- x14 = (x14 << 8) | (x14 >>> 24);
172
- x9 = (x9 + x14) >>> 0;
173
- x4 ^= x9;
174
- x4 = (x4 << 7) | (x4 >>> 25);
175
- }
176
-
177
- block[0] = (x0 + 0x61707865) >>> 0;
178
- block[1] = (x1 + 0x3320646e) >>> 0;
179
- block[2] = (x2 + 0x79622d32) >>> 0;
180
- block[3] = (x3 + 0x6b206574) >>> 0;
181
- block[4] = (x4 + k0) >>> 0;
182
- block[5] = (x5 + k1) >>> 0;
183
- block[6] = (x6 + k2) >>> 0;
184
- block[7] = (x7 + k3) >>> 0;
185
- block[8] = (x8 + k4) >>> 0;
186
- block[9] = (x9 + k5) >>> 0;
187
- block[10] = (x10 + k6) >>> 0;
188
- block[11] = (x11 + k7) >>> 0;
189
- block[12] = (x12 + counter) >>> 0;
190
- block[13] = (x13 + n0) >>> 0;
191
- block[14] = (x14 + n1) >>> 0;
192
- block[15] = (x15 + n2) >>> 0;
193
-
194
- const remaining = length - offset;
195
- if (remaining >= 64) {
196
- if (source) {
197
- for (let w = 0; w < 16; w++) {
198
- const word = block[w];
199
- out[offset] = source[offset] ^ (word & 0xff);
200
- out[offset + 1] = source[offset + 1] ^ ((word >>> 8) & 0xff);
201
- out[offset + 2] = source[offset + 2] ^ ((word >>> 16) & 0xff);
202
- out[offset + 3] = source[offset + 3] ^ ((word >>> 24) & 0xff);
203
- offset += 4;
204
- }
205
- } else {
206
- for (let w = 0; w < 16; w++) {
207
- const word = block[w];
208
- out[offset] = word & 0xff;
209
- out[offset + 1] = (word >>> 8) & 0xff;
210
- out[offset + 2] = (word >>> 16) & 0xff;
211
- out[offset + 3] = (word >>> 24) & 0xff;
212
- offset += 4;
213
- }
214
- }
215
- } else {
216
- for (let i = 0; i < remaining; i++, offset++) {
217
- const stream = (block[i >> 2] >>> ((i & 3) * 8)) & 0xff;
218
- out[offset] = source ? source[offset] ^ stream : stream;
219
- }
220
- }
221
- counter++;
222
- }
223
-
224
- return out;
225
- }
226
-
227
- function chacha20(key, nonce, length) {
228
- const out = new Uint8Array(length);
229
- if (length <= 0) return out;
230
- if (nativeBlockCipher && length >= NATIVE_MIN_BYTES) {
231
- const native = nativeBlockCipher(key, nonce, out);
232
- if (native) return native;
233
- }
234
- return chacha20Into(out, key, nonce, length, null);
235
- }
236
-
237
- // XORs `data` with the keystream in a single pass, without materialising the
238
- // keystream in a separate buffer.
239
- function chacha20Xor(key, nonce, data) {
240
- const out = new Uint8Array(data.length);
241
- if (data.length === 0) return out;
242
- if (nativeBlockCipher && data.length >= NATIVE_MIN_BYTES) {
243
- const native = nativeBlockCipher(key, nonce, out, data);
244
- if (native) return native;
245
- }
246
- return chacha20Into(out, key, nonce, data.length, data);
247
- }
248
-
249
- function decryptPayload(wireBytes, worldId, seed) {
250
- const wire = toUint8Array(wireBytes);
251
- if (wire.length < 8) throw new Error("payload too short");
252
- const view = new DataView(wire.buffer, wire.byteOffset, wire.byteLength);
253
- const packetWordA = view.getUint32(0, true);
254
- const packetWordB = view.getUint32(wire.length - 4, true);
255
- const material = Uint8Array.from(SHARED_CHACHA_MATERIAL);
256
- const worldKey = encoder.encode(`${worldId}${seed}`);
257
- for (let i = 0, l = 0, r = 0; i < 44; i++, l += 7, r += 11) {
258
- material[i] ^= worldKey[i % worldKey.length] ^ (rotl32(packetWordA, l) & 0xff) ^ (rotr32(packetWordB, r) & 0xff);
259
- }
260
- // subarray, not slice: the key and nonce are only read.
261
- const ciphertext = wire.subarray(4, wire.length - 4);
262
- return chacha20Xor(material.subarray(0, 32), material.subarray(32, 44), ciphertext);
263
- }
264
-
265
-
266
- export {
267
- rotl32,
268
- rotr32,
269
- quarterRound,
270
- chacha20,
271
- chacha20Xor,
272
- decryptPayload,
273
- installNativeChaCha20
274
- };
1
+ import {encoder, SHARED_CHACHA_MATERIAL} from "../constants.js";
2
+ import {toUint8Array} from "../protocol/codec/binary.js";
3
+
4
+ function rotl32(x, n) {
5
+ n &= 31;
6
+ return ((x << n) | (x >>> (32 - n))) >>> 0;
7
+ }
8
+
9
+ function rotr32(x, n) {
10
+ n &= 31;
11
+ return ((x >>> n) | (x << (32 - n))) >>> 0;
12
+ }
13
+
14
+ function quarterRound(state, a, b, c, d) {
15
+ state[a] = (state[a] + state[b]) >>> 0;
16
+ state[d] ^= state[a];
17
+ state[d] = rotl32(state[d], 16);
18
+ state[c] = (state[c] + state[d]) >>> 0;
19
+ state[b] ^= state[c];
20
+ state[b] = rotl32(state[b], 12);
21
+ state[a] = (state[a] + state[b]) >>> 0;
22
+ state[d] ^= state[a];
23
+ state[d] = rotl32(state[d], 8);
24
+ state[c] = (state[c] + state[d]) >>> 0;
25
+ state[b] ^= state[c];
26
+ state[b] = rotl32(state[b], 7);
27
+ }
28
+
29
+ // Optional native backend. Node's OpenSSL exposes a raw `chacha20` stream cipher
30
+ // whose keystream is identical to this implementation, and it is ~27x faster on
31
+ // large payloads. It is installed by src/node.js rather than imported here so
32
+ // that browser bundles never see a `node:crypto` specifier.
33
+ let nativeBlockCipher = null;
34
+
35
+ function installNativeChaCha20(cipherFactory) {
36
+ nativeBlockCipher = typeof cipherFactory === "function" ? cipherFactory : null;
37
+ }
38
+
39
+ // Native call overhead dominates below roughly this size; measured crossover is
40
+ // near 150 bytes, so stay in JS for the small per-tick payloads.
41
+ const NATIVE_MIN_BYTES = 256;
42
+
43
+ // Reused across blocks: the keystream words for one 64-byte block. Safe because
44
+ // generation is synchronous and single-threaded.
45
+ const SCRATCH_BLOCK = new Uint32Array(16);
46
+
47
+ function readLe32(bytes, offset) {
48
+ return (bytes[offset] | (bytes[offset + 1] << 8) | (bytes[offset + 2] << 16) | (bytes[offset + 3] << 24)) >>> 0;
49
+ }
50
+
51
+ // Writes `length` keystream bytes into `out` starting at 0, XORing against
52
+ // `source` when supplied. Keeping generation and XOR in one pass avoids
53
+ // allocating a full second buffer for the keystream.
54
+ function chacha20Into(out, key, nonce, length, source) {
55
+ const k0 = readLe32(key, 0), k1 = readLe32(key, 4), k2 = readLe32(key, 8), k3 = readLe32(key, 12);
56
+ const k4 = readLe32(key, 16), k5 = readLe32(key, 20), k6 = readLe32(key, 24), k7 = readLe32(key, 28);
57
+ const n0 = readLe32(nonce, 0), n1 = readLe32(nonce, 4), n2 = readLe32(nonce, 8);
58
+
59
+ let counter = 0;
60
+ let offset = 0;
61
+ const block = SCRATCH_BLOCK;
62
+
63
+ while (offset < length) {
64
+ let x0 = 0x61707865, x1 = 0x3320646e, x2 = 0x79622d32, x3 = 0x6b206574;
65
+ let x4 = k0, x5 = k1, x6 = k2, x7 = k3;
66
+ let x8 = k4, x9 = k5, x10 = k6, x11 = k7;
67
+ let x12 = counter, x13 = n0, x14 = n1, x15 = n2;
68
+
69
+ for (let i = 0; i < 10; i++) {
70
+ // column rounds
71
+ x0 = (x0 + x4) >>> 0;
72
+ x12 ^= x0;
73
+ x12 = (x12 << 16) | (x12 >>> 16);
74
+ x8 = (x8 + x12) >>> 0;
75
+ x4 ^= x8;
76
+ x4 = (x4 << 12) | (x4 >>> 20);
77
+ x0 = (x0 + x4) >>> 0;
78
+ x12 ^= x0;
79
+ x12 = (x12 << 8) | (x12 >>> 24);
80
+ x8 = (x8 + x12) >>> 0;
81
+ x4 ^= x8;
82
+ x4 = (x4 << 7) | (x4 >>> 25);
83
+
84
+ x1 = (x1 + x5) >>> 0;
85
+ x13 ^= x1;
86
+ x13 = (x13 << 16) | (x13 >>> 16);
87
+ x9 = (x9 + x13) >>> 0;
88
+ x5 ^= x9;
89
+ x5 = (x5 << 12) | (x5 >>> 20);
90
+ x1 = (x1 + x5) >>> 0;
91
+ x13 ^= x1;
92
+ x13 = (x13 << 8) | (x13 >>> 24);
93
+ x9 = (x9 + x13) >>> 0;
94
+ x5 ^= x9;
95
+ x5 = (x5 << 7) | (x5 >>> 25);
96
+
97
+ x2 = (x2 + x6) >>> 0;
98
+ x14 ^= x2;
99
+ x14 = (x14 << 16) | (x14 >>> 16);
100
+ x10 = (x10 + x14) >>> 0;
101
+ x6 ^= x10;
102
+ x6 = (x6 << 12) | (x6 >>> 20);
103
+ x2 = (x2 + x6) >>> 0;
104
+ x14 ^= x2;
105
+ x14 = (x14 << 8) | (x14 >>> 24);
106
+ x10 = (x10 + x14) >>> 0;
107
+ x6 ^= x10;
108
+ x6 = (x6 << 7) | (x6 >>> 25);
109
+
110
+ x3 = (x3 + x7) >>> 0;
111
+ x15 ^= x3;
112
+ x15 = (x15 << 16) | (x15 >>> 16);
113
+ x11 = (x11 + x15) >>> 0;
114
+ x7 ^= x11;
115
+ x7 = (x7 << 12) | (x7 >>> 20);
116
+ x3 = (x3 + x7) >>> 0;
117
+ x15 ^= x3;
118
+ x15 = (x15 << 8) | (x15 >>> 24);
119
+ x11 = (x11 + x15) >>> 0;
120
+ x7 ^= x11;
121
+ x7 = (x7 << 7) | (x7 >>> 25);
122
+
123
+ // diagonal rounds
124
+ x0 = (x0 + x5) >>> 0;
125
+ x15 ^= x0;
126
+ x15 = (x15 << 16) | (x15 >>> 16);
127
+ x10 = (x10 + x15) >>> 0;
128
+ x5 ^= x10;
129
+ x5 = (x5 << 12) | (x5 >>> 20);
130
+ x0 = (x0 + x5) >>> 0;
131
+ x15 ^= x0;
132
+ x15 = (x15 << 8) | (x15 >>> 24);
133
+ x10 = (x10 + x15) >>> 0;
134
+ x5 ^= x10;
135
+ x5 = (x5 << 7) | (x5 >>> 25);
136
+
137
+ x1 = (x1 + x6) >>> 0;
138
+ x12 ^= x1;
139
+ x12 = (x12 << 16) | (x12 >>> 16);
140
+ x11 = (x11 + x12) >>> 0;
141
+ x6 ^= x11;
142
+ x6 = (x6 << 12) | (x6 >>> 20);
143
+ x1 = (x1 + x6) >>> 0;
144
+ x12 ^= x1;
145
+ x12 = (x12 << 8) | (x12 >>> 24);
146
+ x11 = (x11 + x12) >>> 0;
147
+ x6 ^= x11;
148
+ x6 = (x6 << 7) | (x6 >>> 25);
149
+
150
+ x2 = (x2 + x7) >>> 0;
151
+ x13 ^= x2;
152
+ x13 = (x13 << 16) | (x13 >>> 16);
153
+ x8 = (x8 + x13) >>> 0;
154
+ x7 ^= x8;
155
+ x7 = (x7 << 12) | (x7 >>> 20);
156
+ x2 = (x2 + x7) >>> 0;
157
+ x13 ^= x2;
158
+ x13 = (x13 << 8) | (x13 >>> 24);
159
+ x8 = (x8 + x13) >>> 0;
160
+ x7 ^= x8;
161
+ x7 = (x7 << 7) | (x7 >>> 25);
162
+
163
+ x3 = (x3 + x4) >>> 0;
164
+ x14 ^= x3;
165
+ x14 = (x14 << 16) | (x14 >>> 16);
166
+ x9 = (x9 + x14) >>> 0;
167
+ x4 ^= x9;
168
+ x4 = (x4 << 12) | (x4 >>> 20);
169
+ x3 = (x3 + x4) >>> 0;
170
+ x14 ^= x3;
171
+ x14 = (x14 << 8) | (x14 >>> 24);
172
+ x9 = (x9 + x14) >>> 0;
173
+ x4 ^= x9;
174
+ x4 = (x4 << 7) | (x4 >>> 25);
175
+ }
176
+
177
+ block[0] = (x0 + 0x61707865) >>> 0;
178
+ block[1] = (x1 + 0x3320646e) >>> 0;
179
+ block[2] = (x2 + 0x79622d32) >>> 0;
180
+ block[3] = (x3 + 0x6b206574) >>> 0;
181
+ block[4] = (x4 + k0) >>> 0;
182
+ block[5] = (x5 + k1) >>> 0;
183
+ block[6] = (x6 + k2) >>> 0;
184
+ block[7] = (x7 + k3) >>> 0;
185
+ block[8] = (x8 + k4) >>> 0;
186
+ block[9] = (x9 + k5) >>> 0;
187
+ block[10] = (x10 + k6) >>> 0;
188
+ block[11] = (x11 + k7) >>> 0;
189
+ block[12] = (x12 + counter) >>> 0;
190
+ block[13] = (x13 + n0) >>> 0;
191
+ block[14] = (x14 + n1) >>> 0;
192
+ block[15] = (x15 + n2) >>> 0;
193
+
194
+ const remaining = length - offset;
195
+ if (remaining >= 64) {
196
+ if (source) {
197
+ for (let w = 0; w < 16; w++) {
198
+ const word = block[w];
199
+ out[offset] = source[offset] ^ (word & 0xff);
200
+ out[offset + 1] = source[offset + 1] ^ ((word >>> 8) & 0xff);
201
+ out[offset + 2] = source[offset + 2] ^ ((word >>> 16) & 0xff);
202
+ out[offset + 3] = source[offset + 3] ^ ((word >>> 24) & 0xff);
203
+ offset += 4;
204
+ }
205
+ } else {
206
+ for (let w = 0; w < 16; w++) {
207
+ const word = block[w];
208
+ out[offset] = word & 0xff;
209
+ out[offset + 1] = (word >>> 8) & 0xff;
210
+ out[offset + 2] = (word >>> 16) & 0xff;
211
+ out[offset + 3] = (word >>> 24) & 0xff;
212
+ offset += 4;
213
+ }
214
+ }
215
+ } else {
216
+ for (let i = 0; i < remaining; i++, offset++) {
217
+ const stream = (block[i >> 2] >>> ((i & 3) * 8)) & 0xff;
218
+ out[offset] = source ? source[offset] ^ stream : stream;
219
+ }
220
+ }
221
+ counter++;
222
+ }
223
+
224
+ return out;
225
+ }
226
+
227
+ function chacha20(key, nonce, length) {
228
+ const out = new Uint8Array(length);
229
+ if (length <= 0) return out;
230
+ if (nativeBlockCipher && length >= NATIVE_MIN_BYTES) {
231
+ const native = nativeBlockCipher(key, nonce, out);
232
+ if (native) return native;
233
+ }
234
+ return chacha20Into(out, key, nonce, length, null);
235
+ }
236
+
237
+ // XORs `data` with the keystream in a single pass, without materialising the
238
+ // keystream in a separate buffer.
239
+ function chacha20Xor(key, nonce, data) {
240
+ const out = new Uint8Array(data.length);
241
+ if (data.length === 0) return out;
242
+ if (nativeBlockCipher && data.length >= NATIVE_MIN_BYTES) {
243
+ const native = nativeBlockCipher(key, nonce, out, data);
244
+ if (native) return native;
245
+ }
246
+ return chacha20Into(out, key, nonce, data.length, data);
247
+ }
248
+
249
+ function decryptPayload(wireBytes, worldId, seed) {
250
+ const wire = toUint8Array(wireBytes);
251
+ if (wire.length < 8) throw new Error("payload too short");
252
+ const view = new DataView(wire.buffer, wire.byteOffset, wire.byteLength);
253
+ const packetWordA = view.getUint32(0, true);
254
+ const packetWordB = view.getUint32(wire.length - 4, true);
255
+ const material = Uint8Array.from(SHARED_CHACHA_MATERIAL);
256
+ const worldKey = encoder.encode(`${worldId}${seed}`);
257
+ for (let i = 0, l = 0, r = 0; i < 44; i++, l += 7, r += 11) {
258
+ material[i] ^= worldKey[i % worldKey.length] ^ (rotl32(packetWordA, l) & 0xff) ^ (rotr32(packetWordB, r) & 0xff);
259
+ }
260
+ // subarray, not slice: the key and nonce are only read.
261
+ const ciphertext = wire.subarray(4, wire.length - 4);
262
+ return chacha20Xor(material.subarray(0, 32), material.subarray(32, 44), ciphertext);
263
+ }
264
+
265
+
266
+ export {
267
+ rotl32,
268
+ rotr32,
269
+ quarterRound,
270
+ chacha20,
271
+ chacha20Xor,
272
+ decryptPayload,
273
+ installNativeChaCha20
274
+ };
package/src/events.js CHANGED
@@ -1,39 +1,39 @@
1
- export class EventBus {
2
- #listeners = new Map();
3
-
4
- on(type, callback) {
5
- if (typeof callback !== "function") return this;
6
- if (!this.#listeners.has(type)) this.#listeners.set(type, new Set());
7
- this.#listeners.get(type).add(callback);
8
- return this;
9
- }
10
-
11
- off(type, callback) {
12
- this.#listeners.get(type)?.delete(callback);
13
- return this;
14
- }
15
-
16
- once(type, callback) {
17
- const wrapped = (...args) => {
18
- this.off(type, wrapped);
19
- callback(...args);
20
- };
21
- return this.on(type, wrapped);
22
- }
23
-
24
- emit(type, ...args) {
25
- const listeners = this.#listeners.get(type);
26
- if (!listeners || listeners.size === 0) return;
27
- // Copy only when there is more than one listener: the copy exists so a
28
- // listener may unsubscribe mid-dispatch, and a lone listener removing
29
- // itself cannot disturb an iteration that is already finishing.
30
- for (const callback of listeners.size === 1 ? listeners : [...listeners]) {
31
- try {
32
- callback(...args);
33
- } catch (error) {
34
- if (type === "error" || !this.#listeners.has("error")) throw error;
35
- this.emit("error", error);
36
- }
37
- }
38
- }
39
- }
1
+ export class EventBus {
2
+ #listeners = new Map();
3
+
4
+ on(type, callback) {
5
+ if (typeof callback !== "function") return this;
6
+ if (!this.#listeners.has(type)) this.#listeners.set(type, new Set());
7
+ this.#listeners.get(type).add(callback);
8
+ return this;
9
+ }
10
+
11
+ off(type, callback) {
12
+ this.#listeners.get(type)?.delete(callback);
13
+ return this;
14
+ }
15
+
16
+ once(type, callback) {
17
+ const wrapped = (...args) => {
18
+ this.off(type, wrapped);
19
+ callback(...args);
20
+ };
21
+ return this.on(type, wrapped);
22
+ }
23
+
24
+ emit(type, ...args) {
25
+ const listeners = this.#listeners.get(type);
26
+ if (!listeners || listeners.size === 0) return;
27
+ // Copy only when there is more than one listener: the copy exists so a
28
+ // listener may unsubscribe mid-dispatch, and a lone listener removing
29
+ // itself cannot disturb an iteration that is already finishing.
30
+ for (const callback of listeners.size === 1 ? listeners : [...listeners]) {
31
+ try {
32
+ callback(...args);
33
+ } catch (error) {
34
+ if (type === "error" || !this.#listeners.has("error")) throw error;
35
+ this.emit("error", error);
36
+ }
37
+ }
38
+ }
39
+ }