dredless 0.2.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 (80) hide show
  1. package/README.md +65 -48
  2. package/dist/browser/dredless.global.js +12047 -0
  3. package/dist/browser/dredless.global.js.map +7 -0
  4. package/docs/API_REFERENCE.md +2481 -2481
  5. package/docs/BROWSER_API.md +98 -98
  6. package/docs/NODE_API.md +359 -359
  7. package/package.json +40 -35
  8. package/src/browser-global.js +3 -0
  9. package/src/browser.d.ts +212 -212
  10. package/src/browser.js +133 -133
  11. package/src/client/core.js +1202 -1202
  12. package/src/client/domains/index.js +1818 -1818
  13. package/src/client/index.d.ts +2 -2
  14. package/src/client/index.js +1 -1
  15. package/src/compression/lz4.d.ts +1 -1
  16. package/src/compression/lz4.js +112 -112
  17. package/src/constants.js +74 -74
  18. package/src/crypto/chacha-native.d.ts +9 -9
  19. package/src/crypto/chacha-native.js +48 -48
  20. package/src/crypto/chacha.d.ts +25 -25
  21. package/src/crypto/chacha.js +274 -274
  22. package/src/events.js +39 -39
  23. package/src/index.d.ts +2277 -2277
  24. package/src/index.js +125 -125
  25. package/src/network/browser-session.js +291 -291
  26. package/src/network/connection.d.ts +1 -1
  27. package/src/network/connection.js +31 -31
  28. package/src/network/cookies.js +85 -85
  29. package/src/network/http.js +34 -34
  30. package/src/network/index.d.ts +4 -4
  31. package/src/network/index.js +4 -4
  32. package/src/network/servers.d.ts +7 -7
  33. package/src/network/servers.js +133 -133
  34. package/src/network/session.d.ts +7 -7
  35. package/src/network/session.js +320 -320
  36. package/src/network/ships.d.ts +12 -12
  37. package/src/network/ships.js +73 -73
  38. package/src/node.d.ts +2 -2
  39. package/src/node.js +8 -8
  40. package/src/protocol/codec/binary.d.ts +3 -3
  41. package/src/protocol/codec/binary.js +52 -52
  42. package/src/protocol/codec/msgpack.d.ts +3 -3
  43. package/src/protocol/codec/msgpack.js +555 -555
  44. package/src/protocol/inbound/frame.d.ts +1 -1
  45. package/src/protocol/inbound/frame.js +8 -8
  46. package/src/protocol/inbound/world-payload.d.ts +3 -3
  47. package/src/protocol/inbound/world-payload.js +21 -21
  48. package/src/protocol/index.d.ts +11 -11
  49. package/src/protocol/index.js +19 -19
  50. package/src/protocol/outbound/blueprint.d.ts +22 -22
  51. package/src/protocol/outbound/blueprint.js +36 -36
  52. package/src/protocol/outbound/commands.d.ts +3 -3
  53. package/src/protocol/outbound/commands.js +149 -149
  54. package/src/protocol/outbound/comms.d.ts +28 -28
  55. package/src/protocol/outbound/comms.js +40 -40
  56. package/src/protocol/outbound/inventory.d.ts +64 -64
  57. package/src/protocol/outbound/inventory.js +147 -147
  58. package/src/protocol/outbound/ship-management.d.ts +84 -84
  59. package/src/protocol/outbound/ship-management.js +221 -221
  60. package/src/protocol/outbound/sign.d.ts +18 -18
  61. package/src/protocol/outbound/sign.js +45 -45
  62. package/src/protocol/outbound/ui-config.d.ts +157 -157
  63. package/src/protocol/outbound/ui-config.js +578 -578
  64. package/src/runtime.js +36 -36
  65. package/src/state/generator-maze.d.ts +32 -32
  66. package/src/state/generator-maze.js +370 -370
  67. package/src/state/index.d.ts +3 -3
  68. package/src/state/index.js +3 -3
  69. package/src/state/items.js +20 -20
  70. package/src/state/model/decoder.js +1554 -1554
  71. package/src/state/model/index.d.ts +33 -33
  72. package/src/state/model/index.js +2 -2
  73. package/src/state/model/loader-config.js +1020 -1020
  74. package/src/state/model/reader.js +69 -69
  75. package/src/state/model/state.js +1257 -1257
  76. package/src/state/overworld.js +72 -72
  77. package/src/state/tilesets.js +53 -53
  78. package/src/state/world/index.d.ts +29 -29
  79. package/src/state/world/index.js +180 -180
  80. 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
+ }