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
101 changes: 51 additions & 50 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,95 +1,96 @@
name: Verify
on: [push, pull_request, workflow_dispatch]

on:
push:
pull_request:
workflow_dispatch:

concurrency:
group: verify-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: react-data-inspector-ci-${{ github.ref }}
cancel-in-progress: false

permissions:
contents: read

jobs:
test:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
react: ['18.3.1', '19']
react: ['18.3.1', '19.3.0']
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- name: Check out repository
uses: actions/checkout@v7
- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: 24
cache: npm
- run: npm ci
- run: npm install --no-save react@${{ matrix.react }} react-dom@${{ matrix.react }}
- run: npm run check
- run: npx playwright install --with-deps chromium firefox webkit
- run: npm run test:e2e
- run: npm run benchmark
- uses: actions/upload-artifact@v4
if: always()
# Diagnostic uploads must not fail verification when org storage is full.
cache-dependency-path: package-lock.json
- name: Install dependencies
run: npm ci
- name: Select React version
run: npm install --no-save --ignore-scripts react@${{ matrix.react }} react-dom@${{ matrix.react }}
- name: Run quality gate
run: npm run check
- name: Install browser engines
run: npx playwright install --with-deps chromium firefox webkit
- name: Run browser suite
run: npm run test:e2e
- name: Run model benchmarks
run: npm run benchmark
- name: Preserve failure evidence
if: failure()
continue-on-error: true
uses: actions/upload-artifact@v7
with:
name: evidence-react-${{ matrix.react }}
if-no-files-found: ignore
retention-days: 7
path: |
test-results/
playwright-report/
benchmarks/results.json

verify:
name: Verified
if: always()
needs: test
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- name: Require every React version to pass
env:
RESULT: ${{ needs.test.result }}
run: test "$RESULT" = success

publish:
name: Publish beta package
needs: verify
if: github.ref_type == 'tag' && startsWith(github.ref_name, 'v')
runs-on: ubuntu-latest
environment: npm
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 24
registry-url: https://registry.npmjs.org
- run: npm ci
- run: node scripts/validate-release.mjs
- run: npm run build
- run: npm run test:package
- name: Publish verified beta with provenance
run: npm publish --tag beta --access public --provenance

deploy:
name: Deploy website
needs: [verify, publish]
if: always() && needs.verify.result == 'success' && github.event_name != 'pull_request' && ((github.ref_type == 'tag' && needs.publish.result == 'success') || (github.ref_type != 'tag' && needs.publish.result == 'skipped'))
runs-on: ubuntu-latest
needs: verify
if: "needs.verify.result == 'success' && github.event_name != 'pull_request' && github.ref_type != 'tag'"
runs-on: ubuntu-24.04
environment:
name: ${{ (github.ref == 'refs/heads/main' || github.ref_type == 'tag') && 'production' || 'preview' }}
name: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
url: ${{ steps.deploy.outputs.url }}
env:
VERCEL_ORG_ID: ${{ vars.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ vars.VERCEL_PROJECT_ID }}
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
DEPLOY_ENVIRONMENT: ${{ (github.ref == 'refs/heads/main' || github.ref_type == 'tag') && 'production' || 'preview' }}
DEPLOY_ENVIRONMENT: ${{ github.ref == 'refs/heads/main' && 'production' || 'preview' }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- name: Check out repository
uses: actions/checkout@v7
- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: 24
cache: npm
- run: npm ci
- run: npm run build:website
cache-dependency-path: package-lock.json
- name: Install dependencies
run: npm ci
- name: Build verified website
run: npm run build:website
env:
REQUIRE_NPM_PUBLICATION: 'true'
- name: Deploy verified website
Expand Down
191 changes: 191 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
name: Release

on:
release:
types:
- published

permissions:
contents: read

concurrency:
group: npm-nipe-solutions-react-data-inspector-stable
cancel-in-progress: false

jobs:
verify:
if: github.event.release.prerelease == false
runs-on: ubuntu-24.04
timeout-minutes: 60
outputs:
tarball: ${{ steps.release.outputs.tarball }}
steps:
- name: Check out repository
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Require a release from main
run: git merge-base --is-ancestor HEAD origin/main
- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: 24
cache: npm
cache-dependency-path: package-lock.json
- name: Install dependencies
run: npm ci
- name: Audit dependencies
run: npm audit --audit-level=moderate
- name: Check formatting
run: npm run format:check
- name: Check types
run: npm run typecheck
- name: Run unit and component tests
run: npm test
- name: Check release policy
run: npm run test:release-policy
- name: Build package
run: npm run build
- name: Build website
run: npm run build:website
- name: Verify website
run: npm run test:website
- name: Install browser engines
run: npx playwright install --with-deps chromium firefox webkit
- name: Run browser suite
run: npm run test:e2e
- name: Verify and preserve release artifact
id: release
run: npm run release:check -- --dry-run --output release-artifact
- name: Run model benchmarks
run: npm run benchmark
- name: Run model lifetime benchmark
run: npm run benchmark:memory
- name: Run browser benchmark
run: npm run benchmark:browser
- name: Upload verified release artifact
uses: actions/upload-artifact@v7
with:
name: npm-package-stable
path: release-artifact
if-no-files-found: error
retention-days: 7

publish:
needs: verify
environment: npm
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
id-token: write
steps:
- name: Set up Node.js for trusted publishing
uses: actions/setup-node@v7
with:
node-version: 24
registry-url: https://registry.npmjs.org
- name: Download verified release artifact
uses: actions/download-artifact@v8
with:
name: npm-package-stable
path: release-artifact
- name: Validate and publish verified artifact
env:
RELEASE_TARBALL: ${{ needs.verify.outputs.tarball }}
working-directory: release-artifact
run: |
set -euo pipefail

expected_tarball="nipe-solutions-react-data-inspector-1.0.0.tgz"
manifest_file="release-manifest.json"
if [[ ! "$RELEASE_TARBALL" =~ ^[A-Za-z0-9._-]+$ ]] || [[ "$RELEASE_TARBALL" != "$expected_tarball" ]]; then
echo "Unsafe release tarball: expected $expected_tarball" >&2
exit 1
fi

shopt -s nullglob dotglob
entries=(*)
if (( ${#entries[@]} != 2 )); then
echo "Artifact must contain only the tarball and release manifest" >&2
exit 1
fi
if [[ ! -f "$RELEASE_TARBALL" ]] || [[ ! -f "$manifest_file" ]]; then
echo "Verified tarball or release manifest is missing" >&2
exit 1
fi

node --input-type=module <<'NODE'
import assert from 'node:assert/strict'
import { createHash } from 'node:crypto'
import { readFile } from 'node:fs/promises'

const tarball = process.env.RELEASE_TARBALL
const manifest = JSON.parse(await readFile('release-manifest.json', 'utf8'))
const expectedFiles = [
'LICENSE',
'README.md',
'dist/index.cjs',
'dist/index.d.cts',
'dist/index.d.ts',
'dist/index.js',
'dist/styles.css',
'package.json',
]
const version = process.env.GITHUB_REF_NAME.replace(/^v/, '')
assert.equal(process.env.GITHUB_REF_NAME, `v${version}`)
assert.deepEqual(Object.keys(manifest).sort(), [
'channel',
'filename',
'files',
'integrity',
'name',
'sha512',
'version',
])
assert.equal(manifest.name, '@nipe-solutions/react-data-inspector')
assert.equal(manifest.version, version)
assert.equal(manifest.version, '1.0.0')
assert.equal(manifest.channel, 'latest')
assert.equal(manifest.filename, tarball)
assert.deepEqual(manifest.files, expectedFiles)
assert.match(manifest.sha512, /^[0-9a-f]{128}$/)
assert.match(manifest.integrity, /^sha512-[A-Za-z0-9+/]+={0,2}$/)

const digest = createHash('sha512').update(await readFile(tarball)).digest()
assert.equal(manifest.sha512, digest.toString('hex'))
assert.equal(manifest.integrity, `sha512-${digest.toString('base64')}`)
NODE

npm publish --ignore-scripts --provenance --access public --tag latest "$RELEASE_TARBALL"

deploy:
name: Deploy released website
needs: publish
runs-on: ubuntu-24.04
environment:
name: production
url: ${{ steps.deploy.outputs.url }}
env:
VERCEL_ORG_ID: ${{ vars.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ vars.VERCEL_PROJECT_ID }}
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
DEPLOY_ENVIRONMENT: production
steps:
- name: Check out repository
uses: actions/checkout@v7
- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: 24
cache: npm
cache-dependency-path: package-lock.json
- name: Install dependencies
run: npm ci
- name: Build published website
run: npm run build:website
env:
REQUIRE_NPM_PUBLICATION: 'true'
EXPECTED_NPM_VERSION: '1.0.0'
- name: Deploy released website
id: deploy
run: node scripts/deploy-website.mjs
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# Changelog

## 0.1.0-alpha.0 — unreleased
## 1.0.0 — 2026-09-30

Stable read-only inspector for JavaScript object graphs, including real JavaScript types, circular and shared references, descriptor-safe discovery, controlled expansion and selection, bounded search, grouped large values, keyboard navigation, scoped styling, targeted slots, custom types and actions, classic presentation, and unstyled mode.

The stable contract supports React 18.3 and React 19, TypeScript, ESM and CommonJS, server rendering and hydration. Package verification now installs the exact tarball into isolated React 18 and 19 consumers, enforces the public archive inventory and size budgets, and prevents machine-level npm configuration from affecting release evidence.

Publication uses a separately verified artifact, npm trusted publishing, provenance, and a protected release workflow. Automated unit, browser, accessibility, website, package, and benchmark coverage accompanies the release; the remaining human assistive-technology and physical-device qualification work is documented in [release readiness](docs/release-readiness.md).

## 0.1.0-beta.0 — 2026-09-07

Initial read-only inspector with real JavaScript types, circular/shared reference tracking, descriptor-safe child discovery, grouped large values, bounded search, controlled expansion and selection, copying, keyboard navigation, CSS variables, slots, custom types/actions, and unstyled mode.

Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

A structured JavaScript data inspector for React: inspect the value you actually have.

**Beta release channel.** [Website](https://react-data-inspector.nipesolutions.com) · [Playground](https://react-data-inspector.nipesolutions.com/playground) · [Documentation](https://react-data-inspector.nipesolutions.com/docs). Run `npm install && npm run dev` locally. See [release readiness](docs/release-readiness.md) before production adoption.
**Stable 1.0 release.** [Website](https://react-data-inspector.nipesolutions.com) · [Playground](https://react-data-inspector.nipesolutions.com/playground) · [Documentation](https://react-data-inspector.nipesolutions.com/docs). Run `npm install && npm run dev` locally. Review the [release evidence and remaining manual audits](docs/release-readiness.md) for your adoption requirements.

```tsx
import { DataInspector } from '@nipe-solutions/react-data-inspector'
Expand All @@ -11,10 +11,10 @@ import '@nipe-solutions/react-data-inspector/styles.css'
;<DataInspector value={data} />
```

Install the beta release:
Install the package:

```sh
npm install @nipe-solutions/react-data-inspector@beta
npm install @nipe-solutions/react-data-inspector
```

## Why this exists
Expand Down Expand Up @@ -53,7 +53,7 @@ Prefer quoted keys and object-viewer syntax? Set `presentation="classic"`; see [

See the [compiled customization examples](examples/customization.tsx), [API reference](docs/api.md), [architecture and type matrix](docs/architecture.md), and [performance methodology](benchmarks/README.md).

The beta is read-only; editing is not part of the public API. Getters are not evaluated, promises are not awaited, functions are not executed, and WeakMap/WeakSet contents remain opaque. Collection paths are not presented as JSON Pointers.
The inspector is read-only; editing is not part of the public API. Getters are not evaluated, promises are not awaited, functions are not executed, and WeakMap/WeakSet contents remain opaque. Collection paths are not presented as JSON Pointers.

## Development

Expand Down
Loading