Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/workflows/typescript-bindings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ jobs:
os: [ubuntu-latest, macos-14, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v7
- uses: actions/setup-node@v6
with:
node-version: "20"
node-version: "22"
- uses: dtolnay/rust-toolchain@stable
- name: Install deps and run tests
run: |
Expand All @@ -26,13 +26,13 @@ jobs:
name: Test TypeScript Bindings (Alpine/musl)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tests in node:20-alpine
- uses: actions/checkout@v7
- name: Run tests in node:22-alpine
run: |
docker run --rm \
-v "${{ github.workspace }}:/repo" \
-w "/repo/bindings/typescript/docprims" \
node:20-alpine \
node:22-alpine \
sh -lc '
set -eu
apk add --no-cache bash curl build-base python3 ca-certificates
Expand Down
30 changes: 15 additions & 15 deletions .github/workflows/typescript-napi-prebuilds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ jobs:
name: Build Linux prebuilds
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: '20'
node-version: '22'
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install Zig
Expand Down Expand Up @@ -61,11 +61,11 @@ jobs:
name: Build Linux arm64 prebuild (native)
runs-on: ubuntu-latest-arm64-s
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: '20'
node-version: '22'
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install Node dependencies
Expand All @@ -89,11 +89,11 @@ jobs:
name: Build macOS arm64 prebuild
runs-on: macos-14
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: '20'
node-version: '22'
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install Node dependencies
Expand All @@ -117,11 +117,11 @@ jobs:
name: Build Windows x64 prebuild
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: '20'
node-version: '22'
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install Node dependencies
Expand All @@ -146,11 +146,11 @@ jobs:
runs-on: ubuntu-latest
needs: [build-linux, build-linux-arm64, build-macos-arm64, build-windows]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: '20'
node-version: '22'
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install Node dependencies
Expand Down
49 changes: 42 additions & 7 deletions .github/workflows/typescript-npm-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,54 @@ jobs:
steps:
# Note: Do NOT use fetch-tags here. When running from a tag ref,
# it causes a git fetch conflict. The tag is already checked out.
- uses: actions/checkout@v4
- uses: actions/checkout@v7
- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: '20'
node-version: '24'
registry-url: 'https://registry.npmjs.org'
- name: Ensure npm CLI supports OIDC
- name: Ensure npm trusted publishing runtime
env:
MIN_TRUSTED_PUBLISH_NODE: '22.14.0'
MIN_TRUSTED_PUBLISH_NPM: '11.5.1'
run: |
set -euo pipefail
version_ge() {
local got="${1#v}"
local min="${2#v}"
local got_major got_minor got_patch min_major min_minor min_patch
IFS=. read -r got_major got_minor got_patch _ <<<"${got}"
IFS=. read -r min_major min_minor min_patch _ <<<"${min}"
got_major="${got_major:-0}"
got_minor="${got_minor:-0}"
got_patch="${got_patch:-0}"
min_major="${min_major:-0}"
min_minor="${min_minor:-0}"
min_patch="${min_patch:-0}"
if [ "${got_major}" -gt "${min_major}" ]; then return 0; fi
if [ "${got_major}" -eq "${min_major}" ] &&
[ "${got_minor}" -gt "${min_minor}" ]; then return 0; fi
if [ "${got_major}" -eq "${min_major}" ] &&
[ "${got_minor}" -eq "${min_minor}" ] &&
[ "${got_patch}" -ge "${min_patch}" ]; then return 0; fi
return 1
}

NODE_VERSION="$(node -p 'process.versions.node')"
if ! version_ge "${NODE_VERSION}" "${MIN_TRUSTED_PUBLISH_NODE}"; then
echo "::error::Node ${NODE_VERSION} < ${MIN_TRUSTED_PUBLISH_NODE}"
exit 1
fi
echo "node: ${NODE_VERSION}"

echo "npm (before): $(npm --version)"
# Trusted publishing requires npm >= 11.5.1
npm install -g npm@11.5.1
echo "npm (after): $(npm --version)"
npm install -g "npm@${MIN_TRUSTED_PUBLISH_NPM}"
NPM_VERSION="$(npm --version)"
if ! version_ge "${NPM_VERSION}" "${MIN_TRUSTED_PUBLISH_NPM}"; then
echo "::error::npm ${NPM_VERSION} < ${MIN_TRUSTED_PUBLISH_NPM}"
exit 1
fi
echo "npm (after): ${NPM_VERSION}"
- name: Validate running from a tag ref
run: |
set -euo pipefail
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/validate-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ jobs:
matrix:
os: [ubuntu-latest, macos-14, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
ref: ${{ inputs.tag }}
- uses: actions/setup-node@v4
- uses: actions/setup-node@v6
with:
node-version: "20"
node-version: "22"
- uses: dtolnay/rust-toolchain@stable
- name: Build and test TypeScript bindings
run: |
Expand All @@ -56,9 +56,9 @@ jobs:
name: Validate TypeScript Bindings (Alpine/musl)
runs-on: ubuntu-latest
container:
image: node:20-alpine
image: node:22-alpine
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
ref: ${{ inputs.tag }}
- name: Install build dependencies
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ members = [
[workspace.package]
version = "0.1.4"
edition = "2021"
rust-version = "1.85.0"
rust-version = "1.88.0"
license = "MIT OR Apache-2.0"
repository = "https://github.com/3leaps/docprims"
authors = ["3leaps Architecture Council"]
Expand Down
23 changes: 14 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# make build - Build all crates

.PHONY: all help bootstrap bootstrap-force tools check test fmt lint build clean version install
.PHONY: precommit prepush deps-check audit deny miri msrv fmt-check
.PHONY: precommit prepush deps-check audit deny miri msrv fmt-check npm-publish-prereqs-check
.PHONY: build-release build-ffi cbindgen
.PHONY: release-clean release-download release-checksums release-sign
.PHONY: release-export-keys release-verify-checksums release-verify-signatures
Expand Down Expand Up @@ -82,7 +82,8 @@ help: ## Show available targets
@echo " deny Run cargo-deny license and advisory checks"
@echo " audit Run cargo-audit security scan"
@echo " miri Run Miri UB detection on unsafe code (nightly)"
@echo " msrv Verify build with MSRV (Rust 1.85)"
@echo " msrv Verify build with MSRV (Rust 1.88.0)"
@echo " npm-publish-prereqs-check Verify npm trusted publishing runtime guard"
@echo " check-windows Cross-check Windows targets (no SDK required)"
@echo ""
@echo "Version management:"
Expand Down Expand Up @@ -235,6 +236,7 @@ fmt-check: ## Check formatting without modifying

lint: ## Run linting (goneat assess or cargo clippy)
@echo "Linting..."
@bash scripts/check-npm-trusted-publish-runtime.sh
@if command -v goneat >/dev/null 2>&1; then \
goneat assess --categories lint; \
else \
Expand All @@ -243,6 +245,9 @@ lint: ## Run linting (goneat assess or cargo clippy)
fi
@echo "[ok] Linting passed"

npm-publish-prereqs-check: ## Verify npm trusted publishing runtime guard
@bash scripts/check-npm-trusted-publish-runtime.sh

deny: ## Run cargo-deny license and advisory checks
@echo "Running cargo-deny..."
@if command -v cargo-deny >/dev/null 2>&1; then \
Expand Down Expand Up @@ -278,14 +283,14 @@ miri: ## Run Miri to detect undefined behavior in unsafe code (requires nightly)
fi
@echo "[ok] Miri passed"

msrv: ## Verify build with Minimum Supported Rust Version (1.85)
@echo "Checking MSRV (1.85)..."
@if rustup run 1.85 cargo --version >/dev/null 2>&1; then \
rustup run 1.85 cargo build --workspace && \
rustup run 1.85 cargo test --workspace; \
msrv: ## Verify build with Minimum Supported Rust Version (1.88.0)
@echo "Checking MSRV (1.88.0)..."
@if rustup run 1.88.0 cargo --version >/dev/null 2>&1; then \
rustup run 1.88.0 cargo build --workspace && \
rustup run 1.88.0 cargo test --workspace; \
else \
echo "[!!] Rust 1.85 not installed. Install with:"; \
echo " rustup install 1.85"; \
echo "[!!] Rust 1.88.0 not installed. Install with:"; \
echo " rustup install 1.88.0"; \
exit 1; \
fi
@echo "[ok] MSRV check passed"
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Content extraction from documents in a permissive licensing toolkit.

[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](LICENSE-MIT)
[![Rust](https://img.shields.io/badge/rust-1.85%2B-orange.svg)](https://www.rust-lang.org/)
[![Rust](https://img.shields.io/badge/rust-1.88%2B-orange.svg)](https://www.rust-lang.org/)

## Overview

Expand Down Expand Up @@ -104,8 +104,10 @@ From a consumer project using `file:` protocol:

### CLI

From the repository root:

```bash
cargo install docprims-cli
cargo install --path crates/docprims-cli
```

## Usage
Expand Down Expand Up @@ -159,7 +161,7 @@ Project documentation conventions (what is canonical vs planning notes):

### Prerequisites

- Rust 1.85+
- Rust 1.88+
- curl (for bootstrap)

### Setup
Expand Down
2 changes: 2 additions & 0 deletions bindings/typescript/docprims/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

TypeScript/Node.js bindings for docprims using a Node-API (N-API) native addon (napi-rs).

Requires Node.js 22 or newer.

## Platform support (v0.1.x)

Supported:
Expand Down
2 changes: 1 addition & 1 deletion bindings/typescript/docprims/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"LICENSE"
],
"engines": {
"node": ">=18"
"node": ">=22"
},
"napi": {
"name": "docprims",
Expand Down
73 changes: 73 additions & 0 deletions scripts/check-npm-trusted-publish-runtime.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env bash
set -euo pipefail

workflow=".github/workflows/typescript-npm-publish.yml"
min_node="22.14.0"
min_npm="11.5.1"

fail() {
echo "error: $*" >&2
exit 1
}

normalize_version() {
local value="${1#v}"
value="$(printf '%s' "$value" | tr -d "\"'")"
value="${value%%[!0-9.]*}"
IFS=. read -r major minor patch _ <<<"$value"
printf '%s.%s.%s\n' "${major:-0}" "${minor:-0}" "${patch:-0}"
}

version_ge() {
local got
local min
got="$(normalize_version "$1")"
min="$(normalize_version "$2")"

IFS=. read -r got_major got_minor got_patch <<<"$got"
IFS=. read -r min_major min_minor min_patch <<<"$min"

if ((got_major > min_major)); then
return 0
fi
if ((got_major == min_major && got_minor > min_minor)); then
return 0
fi
if ((got_major == min_major && got_minor == min_minor && got_patch >= min_patch)); then
return 0
fi
return 1
}

[[ -f "$workflow" ]] || fail "missing workflow: $workflow"

node_version="$(
sed -nE "s/^[[:space:]]*node-version:[[:space:]]*['\"]?([^'\"]+)['\"]?.*/\1/p" "$workflow" | head -n 1
)"
[[ -n "$node_version" ]] || fail "publish workflow has no setup-node node-version"
version_ge "$node_version" "$min_node" || fail "publish workflow uses Node $node_version, need >= $min_node"

declared_min_node="$(
sed -nE "s/.*MIN_TRUSTED_PUBLISH_NODE:[[:space:]]*['\"]?([^'\"]+)['\"]?.*/\1/p" "$workflow" | head -n 1
)"
[[ -n "$declared_min_node" ]] || fail "workflow does not declare MIN_TRUSTED_PUBLISH_NODE"
version_ge "$declared_min_node" "$min_node" || fail "MIN_TRUSTED_PUBLISH_NODE is $declared_min_node, need >= $min_node"

declared_min_npm="$(
sed -nE "s/.*MIN_TRUSTED_PUBLISH_NPM:[[:space:]]*['\"]?([^'\"]+)['\"]?.*/\1/p" "$workflow" | head -n 1
)"
[[ -n "$declared_min_npm" ]] || fail "workflow does not declare MIN_TRUSTED_PUBLISH_NPM"
version_ge "$declared_min_npm" "$min_npm" || fail "MIN_TRUSTED_PUBLISH_NPM is $declared_min_npm, need >= $min_npm"

# shellcheck disable=SC2016
grep -Fq 'npm install -g "npm@${MIN_TRUSTED_PUBLISH_NPM}"' "$workflow" ||
fail "workflow must install the declared npm trusted publishing minimum"
grep -Fq 'NODE_VERSION="$(node -p' "$workflow" ||
fail "workflow must read the active Node runtime version"
grep -Fq 'version_ge "${NODE_VERSION}" "${MIN_TRUSTED_PUBLISH_NODE}"' "$workflow" ||
fail "workflow must hard-fail when Node is below the trusted publishing minimum"
# shellcheck disable=SC2016
grep -Fq 'NPM_VERSION="$(npm --version)"' "$workflow" ||
fail "workflow must hard-fail when npm is below the trusted publishing minimum"

echo "[ok] npm trusted publishing runtime guard passed"
Loading