diff --git a/.github/workflows/js.yml b/.github/workflows/js.yml
index cac77df..42a7e8e 100644
--- a/.github/workflows/js.yml
+++ b/.github/workflows/js.yml
@@ -23,6 +23,16 @@ jobs:
with:
node-version: "24.22.1"
- name: Install dependencies
- run: cd crates/markkit-js && npm install
+ run: cd crates/markkit-js && npm install --ignore-scripts --audit=false --fund=false
- name: Build
- run: cd crates/markkit-js && npx napi build --release
+ run: cd crates/markkit-js && npx --no-install napi build --release --platform
+ - name: Verify build preserved the patched lockfile
+ run: git diff --exit-code -- Cargo.lock
+ - name: Verify installed npm package
+ run: |
+ cd crates/markkit-js
+ npm pack --ignore-scripts --json > "$RUNNER_TEMP/markkit-pack.json"
+ node -e 'const p=require(process.argv[1])[0]; const files=p.files.map(f=>f.path); if(!files.includes("index.js") || !files.some(f=>f.endsWith(".node"))) throw Error("npm package must contain its loader and native binary")' "$RUNNER_TEMP/markkit-pack.json"
+ TARBALL=$(node -e 'console.log(require(process.argv[1])[0].filename)' "$RUNNER_TEMP/markkit-pack.json")
+ npm install --prefix "$RUNNER_TEMP/markkit-npm-smoke" --ignore-scripts --audit=false --fund=false "$PWD/$TARBALL"
+ node -e 'const m=require(process.argv[1]); if(m.extractHtmlSync("
Smoke
").trim()!=="# Smoke") throw Error("native extraction smoke failed")' "$RUNNER_TEMP/markkit-npm-smoke/node_modules/@everruns/markkit"
diff --git a/.github/workflows/publish-js.yml b/.github/workflows/publish-js.yml
index e703314..6fb33e8 100644
--- a/.github/workflows/publish-js.yml
+++ b/.github/workflows/publish-js.yml
@@ -19,12 +19,31 @@ jobs:
with:
node-version: "24.22.1"
registry-url: "https://registry.npmjs.org"
+ - name: Require npm publisher credential
+ if: inputs.dry_run != 'true'
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+ run: |
+ if [ -z "$NODE_AUTH_TOKEN" ]; then
+ echo "::error::NPM_TOKEN is unavailable for this publisher"
+ exit 1
+ fi
- name: Install dependencies
- run: cd crates/markkit-js && npm install
+ run: cd crates/markkit-js && npm install --ignore-scripts --audit=false --fund=false
- name: Build
- run: cd crates/markkit-js && npx napi build --release
+ run: cd crates/markkit-js && npx --no-install napi build --release --platform
+ - name: Verify build preserved the patched lockfile
+ run: git diff --exit-code -- Cargo.lock
+ - name: Verify installed npm package
+ run: |
+ cd crates/markkit-js
+ npm pack --ignore-scripts --json > "$RUNNER_TEMP/markkit-pack.json"
+ node -e 'const p=require(process.argv[1])[0]; const files=p.files.map(f=>f.path); if(!files.includes("index.js") || !files.some(f=>f.endsWith(".node"))) throw Error("npm package must contain its loader and native binary")' "$RUNNER_TEMP/markkit-pack.json"
+ TARBALL=$(node -e 'console.log(require(process.argv[1])[0].filename)' "$RUNNER_TEMP/markkit-pack.json")
+ npm install --prefix "$RUNNER_TEMP/markkit-npm-smoke" --ignore-scripts --audit=false --fund=false "$PWD/$TARBALL"
+ node -e 'const m=require(process.argv[1]); if(m.extractHtmlSync("Smoke
").trim()!=="# Smoke") throw Error("native extraction smoke failed")' "$RUNNER_TEMP/markkit-npm-smoke/node_modules/@everruns/markkit"
- name: Publish
if: inputs.dry_run != 'true'
- run: cd crates/markkit-js && npm publish
+ run: cd crates/markkit-js && npm publish --ignore-scripts
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
diff --git a/.github/workflows/publish-python.yml b/.github/workflows/publish-python.yml
index 4bd1890..69c3b23 100644
--- a/.github/workflows/publish-python.yml
+++ b/.github/workflows/publish-python.yml
@@ -18,10 +18,27 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.12"
+ - name: Require PyPI publisher credential
+ if: inputs.dry_run != 'true'
+ env:
+ TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
+ run: |
+ if [ -z "$TWINE_PASSWORD" ]; then
+ echo "::error::PYPI_API_TOKEN is unavailable for this publisher"
+ exit 1
+ fi
- name: Install maturin
run: pip install maturin twine
- name: Build wheels
run: cd crates/markkit-python && maturin build --release
+ - name: Verify build preserved the patched lockfile
+ run: git diff --exit-code -- Cargo.lock
+ - name: Verify wheel metadata and native import
+ run: |
+ twine check target/wheels/*.whl
+ python -m venv "$RUNNER_TEMP/markkit-wheel-smoke"
+ "$RUNNER_TEMP/markkit-wheel-smoke/bin/python" -m pip install --no-deps target/wheels/*.whl
+ "$RUNNER_TEMP/markkit-wheel-smoke/bin/python" -c 'import markkit_python; assert markkit_python.extract_html_sync("Smoke
").strip() == "# Smoke"'
- name: Publish
if: inputs.dry_run != 'true'
run: twine upload target/wheels/*.whl
diff --git a/.gitignore b/.gitignore
index 84f1074..211833a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,3 +36,10 @@ node_modules/
# WASM build artifacts
*.wasm
+
+# Generated NAPI package artifacts
+crates/markkit-js/*.node
+crates/markkit-js/index.js
+crates/markkit-js/index.d.ts
+crates/markkit-js/package-lock.json
+crates/markkit-js/*.tgz
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 830011d..219fca7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,11 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
## [Unreleased]
+## [0.1.1] - 2026-10-22
+
### Security
- Upgrade the HTTP, spreadsheet and ZIP dependency graph to patched TLS and archive releases.
- Track the workspace lockfile so CI audits the same resolution used by CLI and binding builds.
+ Library consumers must refresh their application lockfiles to receive transitive TLS fixes;
+ a dependency library's lockfile is not inherited.
- Run JavaScript build and packaging workflows on Node.js 24.22.1.
+- Include the generated JavaScript loader and native binary in npm packages and verify installed package loading.
+- Scope npm native artifacts explicitly to Linux x64/glibc; other platforms are not included in this release.
+- Verify Python wheel metadata and native extraction before upload; the wheel publisher targets Linux x64/CPython 3.12.
### Changed
diff --git a/Cargo.lock b/Cargo.lock
index 3252f1f..3b7beee 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1292,7 +1292,7 @@ checksum = "4050469837a6ff301cd14c1f8f24f88549e6d548f24f64e2148eb0f72cebc51f"
[[package]]
name = "markkit"
-version = "0.1.0"
+version = "0.1.1"
dependencies = [
"anyhow",
"async-trait",
@@ -1323,7 +1323,7 @@ dependencies = [
[[package]]
name = "markkit-bench"
-version = "0.1.0"
+version = "0.1.1"
dependencies = [
"anyhow",
"clap",
@@ -1339,7 +1339,7 @@ dependencies = [
[[package]]
name = "markkit-cli"
-version = "0.1.0"
+version = "0.1.1"
dependencies = [
"anyhow",
"clap",
@@ -1352,7 +1352,7 @@ dependencies = [
[[package]]
name = "markkit-eval"
-version = "0.1.0"
+version = "0.1.1"
dependencies = [
"anyhow",
"async-trait",
@@ -1367,7 +1367,7 @@ dependencies = [
[[package]]
name = "markkit-js"
-version = "0.1.0"
+version = "0.1.1"
dependencies = [
"markkit",
"napi",
@@ -1380,7 +1380,7 @@ dependencies = [
[[package]]
name = "markkit-python"
-version = "0.1.0"
+version = "0.1.1"
dependencies = [
"markkit",
"pyo3",
diff --git a/Cargo.toml b/Cargo.toml
index 497a02c..fe4a37d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@ members = [
]
[workspace.package]
-version = "0.1.0"
+version = "0.1.1"
edition = "2024"
license = "MIT"
authors = ["Everruns "]
diff --git a/crates/markkit-cli/Cargo.toml b/crates/markkit-cli/Cargo.toml
index 89cf8bd..21cf10d 100644
--- a/crates/markkit-cli/Cargo.toml
+++ b/crates/markkit-cli/Cargo.toml
@@ -26,7 +26,7 @@ docx = ["markkit/docx"]
spreadsheet = ["markkit/spreadsheet"]
[dependencies]
-markkit = { path = "../markkit", version = "0.1.0", features = ["http_client"] }
+markkit = { path = "../markkit", version = "0.1.1", features = ["http_client"] }
tokio = { workspace = true, features = ["macros", "net", "rt", "rt-multi-thread", "time", "fs"] }
clap.workspace = true
anyhow.workspace = true
diff --git a/crates/markkit-js/README.md b/crates/markkit-js/README.md
new file mode 100644
index 0000000..ccd1d8a
--- /dev/null
+++ b/crates/markkit-js/README.md
@@ -0,0 +1,17 @@
+# @everruns/markkit
+
+Native Node.js bindings for Markkit HTML-to-Markdown extraction.
+
+This npm release supports **Linux x64 with glibc**. It does not include binaries for
+macOS, Windows, ARM64 or musl Linux. Other platforms require a separate future
+native release; Rust and Python package availability is independent.
+
+The package contains its JavaScript loader and native binary. CI verifies a clean
+installation and extraction smoke on Node.js 24.22.1 before publication. Use a
+currently supported Node.js release with its security patches installed.
+
+```js
+const { extractHtmlSync } = require('@everruns/markkit');
+console.log(extractHtmlSync('Hello
'));
+// # Hello
+```
diff --git a/crates/markkit-js/package.json b/crates/markkit-js/package.json
index 1d1df88..2d8b9f0 100644
--- a/crates/markkit-js/package.json
+++ b/crates/markkit-js/package.json
@@ -1,6 +1,6 @@
{
"name": "@everruns/markkit",
- "version": "0.1.0",
+ "version": "0.1.1",
"description": "Extract clean markdown from any format – Node.js bindings",
"main": "index.js",
"types": "index.d.ts",
@@ -17,9 +17,22 @@
},
"files": [
"index.js",
- "index.d.ts"
+ "index.d.ts",
+ "*.node"
],
"devDependencies": {
"@napi-rs/cli": "^3"
- }
+ },
+ "publishConfig": {
+ "access": "public"
+ },
+ "os": [
+ "linux"
+ ],
+ "cpu": [
+ "x64"
+ ],
+ "libc": [
+ "glibc"
+ ]
}
diff --git a/crates/markkit-python/README.md b/crates/markkit-python/README.md
new file mode 100644
index 0000000..fff75d2
--- /dev/null
+++ b/crates/markkit-python/README.md
@@ -0,0 +1,17 @@
+# markkit-python
+
+Native Python bindings for Markkit HTML-to-Markdown extraction.
+
+The current wheel publisher builds for **Linux x64 and CPython 3.12**. It does not
+publish macOS, Windows, ARM64 or other Python-version wheels. Other wheel targets
+require a separate future release; Rust and npm availability is independent.
+
+```python
+import markkit_python
+
+print(markkit_python.extract_html_sync("Hello
"))
+# # Hello
+```
+
+Publication verifies wheel metadata, installs the actual wheel into a clean
+virtual environment and exercises native extraction before upload.
diff --git a/specs/release-process.md b/specs/release-process.md
index 8564025..e7c8219 100644
--- a/specs/release-process.md
+++ b/specs/release-process.md
@@ -35,3 +35,17 @@ version from `Cargo.toml`. Python and npm packages are published separately with
| Rust crate | `cargo publish` | crates.io |
| Python wheel | `maturin build` | PyPI |
| npm package | `napi build` | npm |
+
+## Native package scope and verification
+
+Run the Python and npm publishers from the same verified release tag as Rust.
+The initial npm artifact supports Linux x64/glibc only, and the current Python
+wheel publisher targets Linux x64/CPython 3.12 only. Other platforms and interpreters
+are not claimed as available; a future native release can expand coverage.
+
+Both publishers default to a credential-free dry run. Actual publication requires
+an existing publisher credential before building; missing credentials fail without
+printing values. Do not create credentials or alter permissions to complete a release.
+Before upload, npm installs and loads its packed tarball (loader plus native binary),
+and Python checks metadata and imports the built wheel in a clean virtual environment.
+Both builds must preserve the patched Cargo.lock.