libwz 0.1.0 → 0.1.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.
package/README.md CHANGED
@@ -1,55 +1,232 @@
1
1
  # libwz
2
2
 
3
- > ⚠️ **Vibe Coding / Clean-room Reimplementation / Under Development**
4
- > This project was developed with significant AI assistance (GitHub Copilot).
5
- > It is an independent C++ reimplementation — no code was copied from the
6
- > C# reference (included as a submodule for test data only).
3
+ libwz is a C++23 library for reading, traversing, editing, and exporting
4
+ MapleStory `.wz` archive data. The core parser is implemented in native C++ and
5
+ is exposed through three public surfaces:
7
6
 
8
- A native C++ library for reading and parsing **MapleStory `.wz` game data files**.
9
- Provides C API for FFI consumers and JNI bindings for Java/Kotlin.
7
+ - C++: static libraries for the parser and optional C ABI layer
8
+ - Java: JNI bindings plus Java wrapper classes
9
+ - JavaScript: one ESM package that uses a native Node addon in Node.js and a
10
+ WebAssembly backend when requested or selected by browser bundlers
10
11
 
11
- <!-- [![Build & Publish](https://github.com/toyobayashi/libwz/actions/workflows/build.yml/badge.svg)](https://github.com/toyobayashi/libwz/actions/workflows/build.yml) -->
12
+ The project is an independent clean-room reimplementation guided by the
13
+ HaRepacker/MapleLib behavior in the `Harepacker-resurrected/` submodule. That
14
+ submodule is used as a reference and as a source of test data; source code is not
15
+ copied from it.
16
+
17
+ ## Status
18
+
19
+ This project is under active development. The parser already covers common read,
20
+ traversal, image, sound, Lua, UOL, and editing workflows, but APIs may still
21
+ change before a stable release.
12
22
 
13
23
  ## Features
14
24
 
15
- - Decrypt and parse PKG1-format `.wz` archives across all major MapleStory
16
- regions (GMS, EMS, BMS, Classic, Custom)
17
- - Support for 32-bit and 64-bit WZ file versions
18
- - Hierarchical directory/image traversal with all 16 property types
19
- - Image decompression: DXT3, DXT5, BGRA4444, ARGB1555, RGB565, Form517
20
- - UOL (link) property resolution with cross-file traversal
21
- - Audio extraction (MP3/WAV) from Sound properties
25
+ - PKG1 `.wz` archive parsing with regional MapleStory keys
26
+ - 32-bit and 64-bit WZ version handling
27
+ - Directory and image traversal
28
+ - Property support for null, numeric, string, sub, canvas, vector, convex,
29
+ sound, raw, UOL, Lua, PNG, and video-like/raw data properties
30
+ - UOL and canvas link resolution
31
+ - Canvas/PNG export to PNG bytes or files
32
+ - Sound export to raw MP3/WAV-compatible bytes or files
22
33
  - Lua script decoding
23
- - PNG export from Canvas properties
24
- - C API (`wz_api.h`) for FFI consumers (Python, Node.js, etc.)
25
- - JNI bindings for Java/Kotlin consumers
26
- - Java wrapper classes with `AutoCloseable` resource management
27
- - Node.js native addon and WebAssembly package entries for JavaScript users
34
+ - WZ editing and save-to-disk support in native-capable builds
35
+ - C ABI layer for FFI consumers
36
+ - JNI wrapper with `AutoCloseable` resource management
37
+ - JavaScript ESM wrapper with native Node and WebAssembly backends
28
38
 
29
39
  ## Requirements
30
40
 
31
- - **C++23** compiler with `<expected>` support
32
- - **CMake 3.16+**
33
- - **Git** (for submodules)
41
+ Core C++ build:
42
+
43
+ - CMake 3.16+
44
+ - C++23 compiler with `<expected>` support
45
+ - Git with submodule support
46
+
47
+ Optional bindings:
48
+
49
+ - Java 21 and Maven for JNI/JAR builds
50
+ - Node.js `^20.19.0 || >=22.12.0` for the JavaScript package
51
+ - node-gyp toolchain for the native Node addon
52
+ - Emscripten for the WebAssembly build
53
+
54
+ ## Repository Layout
55
+
56
+ | Path | Purpose |
57
+ |------|---------|
58
+ | `include/wz/` | Public C++ headers |
59
+ | `include/wz/Properties/` | Concrete WZ property types |
60
+ | `include/wz/wz_api.h` | C ABI header |
61
+ | `src/` | C++ implementation |
62
+ | `src/capi/` | C ABI implementation |
63
+ | `src/jni/` | JNI native bridge |
64
+ | `src/node/` | Node-API / emnapi binding |
65
+ | `java/` | Java wrapper and Maven project |
66
+ | `js/` | TypeScript JavaScript wrapper source |
67
+ | `tests/` | C++ and JavaScript tests |
68
+ | `Harepacker-resurrected/` | C# reference and WZ test data submodule |
69
+
70
+ ## Build From Source
34
71
 
35
- ## Quick Start — C++
72
+ Clone with submodules:
36
73
 
37
74
  ```bash
38
75
  git clone --recurse-submodules https://github.com/toyobayashi/libwz.git
39
76
  cd libwz
77
+ ```
40
78
 
41
- cmake -B build -DCMAKE_BUILD_TYPE=Release
42
- cmake --build build
79
+ Build the core C++ libraries:
80
+
81
+ ```bash
82
+ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
83
+ cmake --build build --config Release
84
+ ```
85
+
86
+ Build with JNI enabled:
87
+
88
+ ```bash
89
+ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_JNI=ON
90
+ cmake --build build --config Release
91
+ ```
92
+
93
+ Build the JavaScript package from source:
94
+
95
+ ```bash
96
+ npm install
97
+ npm run build
98
+ ```
99
+
100
+ Build the WebAssembly artifacts:
101
+
102
+ ```bash
103
+ npm install
104
+ npm run build:wasm
105
+ ```
43
106
 
44
- # Run tests
45
- cmake -B build -DBUILD_TESTS=ON
107
+ Run tests:
108
+
109
+ ```bash
110
+ cmake -S . -B build -DBUILD_TESTS=ON
46
111
  cmake --build build
47
112
  ctest --test-dir build
113
+
114
+ npm test
115
+ ```
116
+
117
+ The parser tests use sample WZ files from
118
+ `Harepacker-resurrected/UnitTest_WzFile/WzFiles/`.
119
+
120
+ ## C++ Usage
121
+
122
+ Include the public headers from `include/wz/` and link the `wz` target.
123
+
124
+ ```cpp
125
+ #include <iostream>
126
+ #include "wz/WzFile.h"
127
+ #include "wz/WzImage.h"
128
+ #include "wz/Properties/WzCanvasProperty.h"
129
+
130
+ int main() {
131
+ wz::WzFile file("Character.wz", wz::WzMapleVersion::GMS);
132
+
133
+ if (file.ParseWzFile() != wz::WzFileParseStatus::Success) {
134
+ std::cerr << "failed to parse WZ file\n";
135
+ return 1;
136
+ }
137
+
138
+ auto* root = file.GetWzDirectory();
139
+ if (root == nullptr) return 1;
140
+
141
+ std::cout << "root: " << root->Name() << "\n";
142
+
143
+ for (auto* image : root->WzImages()) {
144
+ auto parsed = image->ParseImage();
145
+ if (!parsed.has_value()) continue;
146
+
147
+ for (auto* prop : *image->WzProperties()) {
148
+ std::cout << image->Name() << "/" << prop->Name() << "\n";
149
+ }
150
+ }
151
+ }
152
+ ```
153
+
154
+ Open a file when you already know the encrypted version or IV:
155
+
156
+ ```cpp
157
+ wz::WzFile byVersion("Character.wz", 87, wz::WzMapleVersion::GMS);
158
+ wz::WzFile byIv("Character.wz", std::array<uint8_t, 4>{0x4D, 0x23, 0xC7, 0x2B});
159
+ ```
160
+
161
+ Look up an object by WZ path:
162
+
163
+ ```cpp
164
+ wz::WzObject* obj = file.GetObjectFromPath("Character/00002000.img/info");
165
+ if (obj != nullptr) {
166
+ std::cout << obj->FullPath() << "\n";
167
+ }
168
+ ```
169
+
170
+ Export a canvas or PNG property:
171
+
172
+ ```cpp
173
+ auto* image = root->GetImageByName("00002000.img");
174
+ if (image != nullptr && image->ParseImage().has_value()) {
175
+ auto* prop = image->GetFromPath("stand/0");
176
+ if (prop != nullptr && prop->PropertyType() == wz::WzPropertyType::Canvas) {
177
+ auto* canvas = static_cast<wz::WzCanvasProperty*>(prop);
178
+ auto* png = canvas->PngProperty();
179
+ if (png != nullptr) {
180
+ auto saved = png->SaveToFile("stand-0.png");
181
+ if (!saved.has_value()) {
182
+ std::cerr << saved.error().message() << "\n";
183
+ }
184
+ }
185
+ }
186
+ }
48
187
  ```
49
188
 
50
- ## Quick Start Java (Maven)
189
+ Create and save a small WZ file:
51
190
 
52
- Add the dependency (available on Maven Central):
191
+ ```cpp
192
+ #include "wz/Properties/WzIntProperty.h"
193
+ #include "wz/Properties/WzStringProperty.h"
194
+
195
+ wz::WzFile out(87, wz::WzMapleVersion::GMS);
196
+ auto* dir = out.GetWzDirectory();
197
+ auto imageResult = dir->CreateImage("Example.img");
198
+ if (!imageResult.has_value()) return 1;
199
+
200
+ auto* image = imageResult.value();
201
+ auto added = image->AddProperty(
202
+ std::make_unique<wz::WzStringProperty>("name", "libwz"));
203
+ if (!added.has_value()) return 1;
204
+
205
+ auto saved = out.SaveToDisk("Example.wz");
206
+ if (!saved.has_value()) return 1;
207
+ ```
208
+
209
+ libwz is built with exceptions disabled. APIs that can fail return
210
+ `wz::Result<T>` (`std::expected<T, wz::Error>`) where practical. Check
211
+ `has_value()` before using a result.
212
+
213
+ ## Java Usage
214
+
215
+ The Java layer lives in the Maven project under `java/`. It wraps the JNI bridge
216
+ with ordinary Java classes such as `WzFile`, `WzDirectory`, `WzImage`, and
217
+ `WzImageProperty`.
218
+
219
+ Build the JNI library and package the JAR locally:
220
+
221
+ ```bash
222
+ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_JNI=ON
223
+ cmake --build build --config Release
224
+
225
+ cd java
226
+ mvn package
227
+ ```
228
+
229
+ When consuming a published artifact, the Maven coordinates are:
53
230
 
54
231
  ```xml
55
232
  <dependency>
@@ -59,107 +236,291 @@ Add the dependency (available on Maven Central):
59
236
  </dependency>
60
237
  ```
61
238
 
62
- Alternatively, from GitHub Packages (requires authentication):
239
+ Open and traverse a WZ file:
240
+
241
+ ```java
242
+ import io.github.toyobayashi.libwz.WzDirectory;
243
+ import io.github.toyobayashi.libwz.WzEnums.MapleVersion;
244
+ import io.github.toyobayashi.libwz.WzEnums.ParseStatus;
245
+ import io.github.toyobayashi.libwz.WzFile;
246
+ import io.github.toyobayashi.libwz.WzImage;
247
+
248
+ public final class ReadWz {
249
+ public static void main(String[] args) {
250
+ try (WzFile file = new WzFile("Character.wz", MapleVersion.GMS)) {
251
+ ParseStatus status = file.parseWzFile();
252
+ if (status != ParseStatus.SUCCESS) {
253
+ throw new IllegalStateException("parse failed: " + status);
254
+ }
255
+
256
+ WzDirectory root = file.getWzDirectory();
257
+ System.out.println(root.getName());
258
+
259
+ for (WzImage image : root.wzImages()) {
260
+ image.parseImage();
261
+ System.out.println(image.getName());
262
+ }
263
+ }
264
+ }
265
+ }
266
+ ```
267
+
268
+ Read properties and export a canvas:
63
269
 
64
- ```xml
65
- <repository>
66
- <id>github</id>
67
- <url>https://maven.pkg.github.com/toyobayashi/libwz</url>
68
- </repository>
270
+ ```java
271
+ import io.github.toyobayashi.libwz.WzCanvasProperty;
272
+ import io.github.toyobayashi.libwz.WzFile;
273
+ import io.github.toyobayashi.libwz.WzImage;
274
+ import io.github.toyobayashi.libwz.WzImageProperty;
275
+ import static io.github.toyobayashi.libwz.WzEnums.MapleVersion.GMS;
276
+
277
+ try (WzFile file = new WzFile("Character.wz", GMS)) {
278
+ file.parseWzFile();
279
+
280
+ WzImage image = file.getWzDirectory().getImageByName("00002000.img");
281
+ image.parseImage();
282
+
283
+ WzImageProperty prop = image.getFromPath("stand/0");
284
+ if (prop instanceof WzCanvasProperty canvas) {
285
+ canvas.saveToFile("stand-0.png");
286
+ }
287
+ }
69
288
  ```
70
289
 
71
- Authenticate with a [GitHub personal access token](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-apache-maven-registry#authenticating-to-github-packages):
290
+ Look up by WZ path:
72
291
 
73
- ```xml
74
- <!-- ~/.m2/settings.xml -->
75
- <server>
76
- <id>github</id>
77
- <username>YOUR_GITHUB_USERNAME</username>
78
- <password>YOUR_GITHUB_TOKEN</password>
79
- </server>
292
+ ```java
293
+ var object = file.getObjectFromPath("Character/00002000.img/info");
294
+ if (object != null) {
295
+ System.out.println(object.getName());
296
+ }
297
+ ```
298
+
299
+ `WzFile` owns the native file handle and implements `AutoCloseable`; use
300
+ try-with-resources. Objects returned from a file, directory, image, or property
301
+ are borrowed wrappers and become invalid after the owning file is closed.
302
+
303
+ ## JavaScript Usage
304
+
305
+ The JavaScript package is ESM-only. Its root entry exports the same wrapper
306
+ classes for native Node and WebAssembly:
307
+
308
+ ```js
309
+ import {
310
+ init,
311
+ MapleVersion,
312
+ ParseStatus,
313
+ WzBinaryProperty,
314
+ WzCanvasProperty,
315
+ WzFile,
316
+ getWzBindingType
317
+ } from 'libwz'
318
+ ```
319
+
320
+ When installed from npm after publication:
321
+
322
+ ```bash
323
+ npm install libwz
324
+ ```
325
+
326
+ When using the repository directly:
327
+
328
+ ```bash
329
+ npm install
330
+ npm run build
331
+ ```
332
+
333
+ ### Node.js Native Backend
334
+
335
+ In Node.js, the package tries to install the native addon when imported. Calling
336
+ `init()` is still supported and is a no-op when native loading succeeded.
337
+
338
+ ```js
339
+ import { init, MapleVersion, ParseStatus, WzFile } from 'libwz'
340
+
341
+ await init()
342
+
343
+ using file = new WzFile('Character.wz', MapleVersion.GMS)
344
+ const status = file.parseWzFile()
345
+ if (status !== ParseStatus.SUCCESS) {
346
+ throw new Error(`parse failed: ${status}`)
347
+ }
348
+
349
+ const root = file.getWzDirectory()
350
+ for (const image of root.wzImages()) {
351
+ image.parseImage()
352
+ console.log(image.getName())
353
+ }
354
+ ```
355
+
356
+ JavaScript wrappers support explicit resource management through
357
+ `[Symbol.dispose]()` and `close()`. If your runtime does not support `using`,
358
+ write the cleanup explicitly:
359
+
360
+ ```js
361
+ const file = new WzFile('Character.wz', MapleVersion.GMS)
362
+ try {
363
+ file.parseWzFile()
364
+ console.log(file.getWzDirectory()?.getName())
365
+ } finally {
366
+ file.close()
367
+ }
80
368
  ```
81
369
 
82
- The JAR bundles native libraries for **Windows x86_64**, **Linux x86_64**,
83
- and **macOS ARM64 (Apple Silicon)**. `NativeLibraryLoader` automatically
84
- extracts the correct one at runtime.
370
+ ### WebAssembly Backend
371
+
372
+ Force WebAssembly in Node.js:
373
+
374
+ ```js
375
+ import { init, MapleVersion, WzFile, getWzBindingType } from 'libwz'
376
+
377
+ await init({ forceWasm: true })
378
+ console.log(getWzBindingType()) // "wasm"
379
+
380
+ using file = new WzFile('Character.wz', MapleVersion.GMS)
381
+ file.parseWzFile()
382
+ ```
85
383
 
86
- ## Quick Start JavaScript / Wasm
384
+ Pass a custom Wasm URL when a bundler or CDN serves `libwz.wasm` from another
385
+ location:
87
386
 
88
- The root `libwz` package entry uses the native Node addon in Node.js and the
89
- Wasm build through the package `browser` export in browser bundlers. Both
90
- entries export the same classes and constants, plus one async `init()` function
91
- for the Wasm runtime.
387
+ ```js
388
+ await init(new URL('./assets/libwz.wasm', import.meta.url))
389
+ ```
92
390
 
93
- Node.js requires `^20.19.0 || >=22.12.0`. `process.getBuiltinModule()` exists
94
- in Node.js 20.16.0 and 22.3.0, but the package also relies on the modern
95
- `require(esm)` interoperability that is available by default from Node.js
96
- 20.19.0 and 22.12.0; Node.js 24.x is covered by the `>=22.12.0` range.
391
+ Open from bytes:
97
392
 
98
393
  ```js
99
- import { init, MapleVersion, WzFile } from "libwz";
394
+ import { MapleVersion, WzFile } from 'libwz'
395
+
396
+ const bytes = new Uint8Array(await fileInput.files[0].arrayBuffer())
397
+ using file = WzFile.fromBytes('Character.wz', bytes, MapleVersion.GMS)
398
+ file.parseWzFile()
399
+ ```
100
400
 
101
- await init();
102
- using file = new WzFile("Character.wz", MapleVersion.GMS);
103
- file.parseWzFile();
401
+ For large browser files, use callback-backed input so the Wasm backend can read
402
+ ranges without copying the whole file. In a Worker, `FileReaderSync` is one
403
+ simple way to implement the callback:
404
+
405
+ ```js
406
+ const reader = new FileReaderSync()
407
+
408
+ using file = WzFile.fromBlobSource(
409
+ 'Character.wz',
410
+ blob.size,
411
+ MapleVersion.GMS,
412
+ (offset, length, destination) => {
413
+ const start = Number(offset)
414
+ const end = start + Number(length)
415
+ const bytes = new Uint8Array(
416
+ reader.readAsArrayBuffer(blob.slice(start, end))
417
+ )
418
+ if (destination !== undefined) {
419
+ destination.set(bytes)
420
+ return
421
+ }
422
+ return bytes
423
+ }
424
+ )
104
425
  ```
105
426
 
106
- Pass a custom Wasm URL or path when your bundler or CDN serves the binary from
107
- a different location.
427
+ ### JavaScript Properties
428
+
429
+ Traverse and inspect properties:
108
430
 
109
431
  ```js
110
- import { init } from "libwz";
432
+ const image = file.getWzDirectory()?.getImageByName('00002000.img')
433
+ image?.parseImage()
434
+
435
+ for (const prop of image?.wzProperties() ?? []) {
436
+ console.log(prop.getName(), prop.getPropertyType())
437
+ }
111
438
 
112
- await init(new URL("./assets/libwz.wasm", import.meta.url));
439
+ const info = image?.getFromPath('info')
440
+ const name = info?.getChildByName('name')?.getString()
113
441
  ```
114
442
 
115
- Use `getWzBindingType()` to inspect whether the active backend is `"native"` or
116
- `"wasm"`. If the native addon cannot be loaded, `init()` falls back to Wasm.
117
- In Node.js, pass a Wasm URL or `{ forceWasm: true }` to force the Wasm backend
118
- even when the native addon is available. Path-based APIs still accept normal
119
- host filesystem paths; the Wasm runtime maps them internally.
443
+ Export images and sounds:
444
+
445
+ ```js
446
+ const canvas = image?.getFromPath('stand/0')
447
+ if (canvas instanceof WzCanvasProperty) {
448
+ canvas.saveToFile('stand-0.png')
449
+
450
+ const png = canvas.getPngProperty()
451
+ console.log(png?.getWidth(), png?.getHeight())
452
+ }
453
+ ```
120
454
 
121
- The package publishes one Wasm binary, `dist/libwz.wasm`, and no synchronous or
122
- main-thread Worker wrapper entry.
455
+ ```js
456
+ const sound = image?.getFromPath('sound')
457
+ if (sound instanceof WzBinaryProperty) {
458
+ sound.saveToFile('sound.mp3')
459
+ }
460
+ ```
123
461
 
124
462
  ## Build Options
125
463
 
126
- | Option | Default | Description |
127
- |--------|---------|-------------|
464
+ | CMake option | Default | Description |
465
+ |--------------|---------|-------------|
128
466
  | `BUILD_TESTS` | `ON` | Build Google Test unit tests |
129
- | `BUILD_CAPI` | `ON` | Build C ABI wrapper (`libwz_capi`) |
130
- | `BUILD_JNI` | `OFF` | Build JNI shared library (`libwz_jni`) |
131
-
132
- ## Targets
467
+ | `BUILD_CAPI` | `ON` | Build the C ABI layer |
468
+ | `BUILD_JNI` | `OFF` | Build the JNI shared library |
469
+ | `BUILD_WASM` | `OFF` | Build the WebAssembly target |
133
470
 
134
471
  | Target | Type | Description |
135
472
  |--------|------|-------------|
136
- | `wz` | Static | Core WZ parsing engine |
137
- | `wz_capi` | Static | C ABI layer for FFI consumers |
138
- | `wz_jni` | Shared | JNI native library for Java |
473
+ | `wz` | Static library | Core C++ parser |
474
+ | `wz_capi` | Static library | C ABI wrapper |
475
+ | `wz_jni` | Shared library | JNI native bridge |
476
+ | `wz_wasm` | Emscripten executable | JavaScript/Wasm artifact |
139
477
 
140
- ## Code Map
478
+ ## Development Commands
141
479
 
142
- | Directory | Purpose |
143
- |-----------|---------|
144
- | `include/wz/` | Public C++ headers |
145
- | `include/wz/Properties/` | 16 property type headers |
146
- | `include/wz/Util/` | Binary reader, key gen, path utils |
147
- | `include/wz/wz_api.h` | C ABI (opaque handles, no STL) |
148
- | `src/` | C++ implementation files |
149
- | `src/capi/` | C API implementation |
150
- | `src/jni/` | JNI bindings (`wz_jni.cpp`) |
151
- | `java/` | Java wrapper classes + Maven project |
152
- | `tests/` | Google Test unit tests |
153
- | `Harepacker-resurrected/` | C# reference (submodule, test data only) |
154
-
155
- ## Dependencies
156
-
157
- - [tiny-AES-c](https://github.com/kokke/tiny-AES-c) — AES-256-ECB decryption
158
- - [zlib](https://github.com/madler/zlib) — Image data decompression
159
- - [Google Test](https://github.com/google/googletest) — Unit tests
480
+ ```bash
481
+ # C++
482
+ cmake -S . -B build -DBUILD_TESTS=ON
483
+ cmake --build build
484
+ ctest --test-dir build
485
+
486
+ # Java
487
+ cmake -S . -B build -DBUILD_JNI=ON
488
+ cmake --build build
489
+ (cd java && mvn test)
490
+
491
+ # JavaScript
492
+ npm run build:ts
493
+ npm run build:native
494
+ npm test
495
+ npm run test:wasm
496
+ ```
497
+
498
+ Format and lint:
499
+
500
+ ```bash
501
+ ./format.sh
502
+ ./lint.sh
503
+ npm run lint:js
504
+ ```
505
+
506
+ ## Notes
507
+
508
+ - The C++ core is built with exceptions and RTTI disabled.
509
+ - C++ failure paths use `wz::Result<T>` where possible.
510
+ - Java and JavaScript wrappers translate native failures to Java exceptions or
511
+ JavaScript errors at the binding boundary.
512
+ - JavaScript `saveToDisk()` and path-based file APIs depend on the active
513
+ backend's runtime capabilities. The WebAssembly backend supports host paths in
514
+ Node.js through a mounted filesystem; browser code should prefer bytes or
515
+ callback-backed input.
516
+ - Published Java artifacts are intended to bundle native libraries for Windows
517
+ x86_64, Linux x86_64, and macOS ARM64 through the GitHub Actions release
518
+ workflow.
519
+ - The npm package publishes `dist/index.js`, `dist/index.d.ts`,
520
+ `dist/libwz.js`, and `dist/libwz.wasm`.
160
521
 
161
522
  ## License
162
523
 
163
- MIT. The `Harepacker-resurrected/` submodule (test data reference, not part of
164
- libwz source) contains code under MPL-2.0 and GPL-3.0 — see respective
165
- LICENSE files in that submodule.
524
+ libwz is licensed under the MIT License. The `Harepacker-resurrected/` submodule
525
+ (test data reference, not part of libwz source) has its own licenses; see that
526
+ submodule for details.