diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 8356029..4e2636b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -13,7 +13,7 @@ body: attributes: label: Package and React versions description: Include the package, react, react-dom, and browser versions. - placeholder: '@nipe-solutions/react-swipe-actions 0.1.0-alpha.2; react 19.2.8' + placeholder: '@nipe-solutions/react-swipe-actions 1.0.0; react 19.2.8' validations: required: true - type: input diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 00b34d4..1d2d999 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,7 +16,7 @@ permissions: contents: read concurrency: - group: npm-nipe-solutions-react-swipe-actions-alpha + group: npm-nipe-solutions-react-swipe-actions-stable cancel-in-progress: false jobs: @@ -55,7 +55,7 @@ jobs: - name: Upload verified release artifact uses: actions/upload-artifact@v7 with: - name: npm-package-alpha + name: npm-package-stable path: release-artifact if-no-files-found: error retention-days: 3 @@ -77,7 +77,7 @@ jobs: - name: Download verified release artifact uses: actions/download-artifact@v7 with: - name: npm-package-alpha + name: npm-package-stable path: release-artifact - name: Validate and publish verified artifact env: @@ -87,12 +87,12 @@ jobs: run: | set -euo pipefail - if [[ "$RELEASE_CHANNEL" != "alpha" ]]; then - echo "Release channel must be alpha" >&2 + if [[ "$RELEASE_CHANNEL" != "latest" ]]; then + echo "Release channel must be latest" >&2 exit 1 fi - expected_tarball="nipe-solutions-react-swipe-actions-0.1.0-alpha.3.tgz" + expected_tarball="nipe-solutions-react-swipe-actions-1.0.0.tgz" if [[ ! "$RELEASE_TARBALL" =~ ^[A-Za-z0-9._-]+$ ]] || [[ "$RELEASE_TARBALL" != "$expected_tarball" ]]; then echo "Unsafe release tarball: expected $expected_tarball" >&2 exit 1 diff --git a/.gitignore b/.gitignore index b214ef0..7a07b2e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .worktrees/ -.superpowers/ node_modules/ dist/ coverage/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 9140012..0161ef9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,30 @@ All notable changes are documented in this file. +## [1.0.0] - 2026-09-29 + +### Added + +- Declared the existing component, type, stylesheet, CSS-variable, data-attribute, + keyboard, logical-side, and controlled-state surfaces stable. +- Added protected stable publication through the npm `latest` tag with OIDC + provenance, exact artifact validation, and a SHA-512 manifest. + +### Fixed + +- Isolated packed-consumer installs from unrelated npm script policy while + retaining caller registry and network configuration. +- Updated the development-only `undici` resolution used through `jsdom` to a + patched version. + +### Verified + +- Rechecked React 18 and 19 consumers, ESM and CommonJS loading, TypeScript, + SSR and hydration, Vite, bundle budgets, and the public package inventory. +- Ran the automated Chromium, Firefox, and WebKit interaction matrix together + with keyboard and axe coverage. No physical-device or human screen-reader + run is claimed for this release. + ## [0.1.0-alpha.3] - 2026-09-05 ### Fixed diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 469a33f..7ebefc4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,9 +1,9 @@ # Contributing Issues and pull requests are welcome for reproducible defects, documentation, -tests, and focused improvements to the public contract. The package is in an -alpha phase; discuss a new public API or broad interaction model before writing -an implementation. +tests, and focused improvements to the public contract. Discuss a new public API +or broad interaction model before writing an implementation; compatibility is +maintained within the current major release. ## Local setup @@ -42,9 +42,9 @@ not install or run the browser matrix. evidence. Physical directions are browser behavior, not public state. - Include documentation updates when the exported API, CSS contract, browser policy, or limitations change. -- No Changesets integration is configured for this alpha. Describe the - user-visible changelog entry in the pull request; maintainers update - [CHANGELOG.md](CHANGELOG.md) when preparing a release. +- Describe the user-visible changelog entry in the pull request. Maintainers + update [CHANGELOG.md](CHANGELOG.md) while preparing a release; the repository + does not use Changesets. ## Review evidence diff --git a/README.md b/README.md index c13715c..b45fd2c 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ controlled or default open state. Keep server and first-client state consistent. Support targets the current and previous major Chrome/Chromium, Edge, Firefox, and Safari releases, plus modern Chrome Android and Mobile Safari. It requires Pointer Events, `ResizeObserver`, animation frames, CSS custom properties, and -logical properties. v1 is an alpha and intentionally excludes generic gesture +logical properties. The 1.x contract intentionally excludes generic gesture hooks, nested swipe roots, portals, React Native, `asChild`, and application list lifecycle features. diff --git a/SECURITY.md b/SECURITY.md index e73abf1..1b50dbd 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,10 +2,9 @@ ## Supported versions -Security fixes are evaluated for the current `0.1.0-alpha.0` development line. -Older prereleases are not supported. This policy describes the repository before -the first npm publication; it does not claim that an unlisted registry version -is supported. +Security fixes are evaluated for the current `1.x` release line. Prereleases and +superseded release lines are not supported unless a security advisory states +otherwise. ## Reporting a vulnerability diff --git a/docs/REAL_DEVICE_QA.md b/docs/REAL_DEVICE_QA.md index a3fa753..90fd346 100644 --- a/docs/REAL_DEVICE_QA.md +++ b/docs/REAL_DEVICE_QA.md @@ -5,11 +5,12 @@ An unchecked manual item is pending, not an implied pass. ## Automated coverage -CI exercises Chromium, Firefox, and WebKit with real browser pointer sequences. -It covers horizontal intent, vertical-scroll arbitration, slow and fast release, -pause before release, direction reversal, full-swipe activation and cancellation, -re-grab during settle, group handoff, interactive children, keyboard disclosure, -RTL, reduced motion, resize, pointer cancellation, and accessibility scans. +CI exercises Chromium, Firefox, and WebKit with browser pointer sequences. It +covers horizontal intent, vertical-scroll arbitration, slow and fast release, +pause before release, direction reversal, full-swipe activation and +cancellation, re-grab during settle, group handoff, interactive children, +keyboard disclosure, RTL, reduced motion, resize, pointer cancellation, and axe +accessibility scans. Desktop browser automation cannot faithfully reproduce OS navigation-edge gestures, device touch latency, orientation sensors, or assistive technology on @@ -42,4 +43,6 @@ outside a nested scroll container. ## Manual verified -No physical-device run has been recorded for this release candidate yet. +No physical-device or human screen-reader run was performed for the 1.0.0 +release. The automated browser, keyboard, and axe results are the recorded +release evidence; they do not stand in for the unchecked manual items above. diff --git a/docs/RELEASING.md b/docs/RELEASING.md index 38b86c2..7adb14f 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -12,14 +12,14 @@ procedure for later versions. ## Preconditions - Use Node.js 24 and npm 11.19.0 with a clean, reviewed worktree. -- Confirm the intended version, prerelease tag, and matching unreleased entry - in [CHANGELOG.md](../CHANGELOG.md). +- Confirm the intended version, npm dist-tag, and matching dated entry in + [CHANGELOG.md](../CHANGELOG.md). - Confirm package metadata, exports, license, and repository links still match the [public API](../README.md) and [architecture](architecture.md). - Review the current and previous browser-major policy in - [architecture](architecture.md#browser-policy), including any manual - mobile-edge and container evidence that automated desktop browsers cannot - establish. + [architecture](architecture.md#browser-policy). Record manual mobile-edge, + screen-reader, and container evidence when available; do not infer it from + desktop automation. Install and run the quality evidence: @@ -37,7 +37,7 @@ Build and inspect the exact tarball contents before release automation uses it: ```bash npm run build:dist npm pack --json -tar -tf nipe-solutions-react-swipe-actions-0.1.0-alpha.3.tgz +tar -tf nipe-solutions-react-swipe-actions-1.0.0.tgz npm publish --dry-run --provenance --access public ``` @@ -61,6 +61,6 @@ bypass a missing trusted-publisher configuration. Record the workflow run, published version, provenance link, tarball inventory, browser evidence, and any manual-device checks with the release record. -Each prerelease is published only after a maintainer explicitly approves the -release, confirms the protected environment and triggers the workflow. Until -then, this guide remains a review procedure and dry-run checklist. +Each release is published only after a maintainer explicitly approves it, +confirms the protected environment, and triggers the workflow. Until then, this +guide remains a review procedure and dry-run checklist. diff --git a/docs/architecture.md b/docs/architecture.md index b8ed18c..4c8f2f5 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -234,11 +234,12 @@ content layer because JavaScript owns direct drag and settle coordinates. ## Limitations -The alpha does not provide row removal, undo, confirmation, async state, generic -gesture hooks, virtualization, portals, drag and drop, `asChild`, React Native, -or nested swipe roots. It has no runtime integration dependency for dialogs, -drawers, or Bottom Sheet components. Those containers must allow vertical pan -ownership and should be tested with their actual gesture configuration. +The package does not provide row removal, undo, confirmation, async state, +generic gesture hooks, virtualization, portals, drag and drop, `asChild`, React +Native, or nested swipe roots. It has no runtime integration dependency for +dialogs, drawers, or Bottom Sheet components. Those containers must allow +vertical pan ownership and should be tested with their actual gesture +configuration. Performance cost currently scales with rendered rows and observed elements. Applications with very large datasets should virtualize at the list layer. CSS @@ -262,10 +263,11 @@ keyboard/focus, RTL, reduced motion, SSR import/rendering, browser interaction, package consumers, and CSS/API boundaries. Manual checks are recorded separately and are never implied by an automated -pass. In particular, OS browser back-edge gestures on physical Mobile Safari and -Chrome Android require device testing because desktop automation cannot -faithfully reproduce navigation-edge ownership. Bottom Sheet integrations also -need checks against the consuming sheet version and configuration. +pass. No physical-device or human screen-reader run is part of the 1.0.0 release +record. OS browser back-edge gestures on physical Mobile Safari and Chrome +Android require device testing because desktop automation cannot faithfully +reproduce navigation-edge ownership. Bottom Sheet integrations also need checks +against the consuming sheet version and configuration. ### Native-feel interaction matrix diff --git a/docs/performance.md b/docs/performance.md index 95a932c..49c8092 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -1,7 +1,7 @@ # Performance evidence -This document records measured evidence for the alpha package. It is not a claim -that every application or device will match these timings. +This document records measured evidence for the package. It is not a claim that +every application or device will match these timings. ## Fixture diff --git a/package-lock.json b/package-lock.json index 0e5990b..f0a801a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@nipe-solutions/react-swipe-actions", - "version": "0.1.0-alpha.3", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@nipe-solutions/react-swipe-actions", - "version": "0.1.0-alpha.3", + "version": "1.0.0", "license": "MIT", "devDependencies": { "@axe-core/playwright": "^4.13.0", @@ -3125,9 +3125,9 @@ } }, "node_modules/undici": { - "version": "8.10.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-8.10.1.tgz", - "integrity": "sha512-YQ3WlbqjYMmNpdvDH64jAgLjxuAR9+649calDWhbshYaeQGO2bR4nI94ORJmwI3J9YhoKQnpyGOK+0zlWS5N5Q==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.11.2.tgz", + "integrity": "sha512-u4UB2/IrKdU6lFxumHmmo1a3fCQO5tzQllRorfoRS63txhrB7xTpSn1PftwC4qEHkOaqP95fCWW4lJzwErwzhQ==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index cc1b060..4a35939 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@nipe-solutions/react-swipe-actions", - "version": "0.1.0-alpha.3", + "version": "1.0.0", "description": "Composable swipe actions for React.", "license": "MIT", "repository": { @@ -14,7 +14,7 @@ "publishConfig": { "access": "public", "provenance": true, - "tag": "alpha" + "tag": "latest" }, "type": "module", "engines": { @@ -55,7 +55,7 @@ "verify:website:browser": "node scripts/verify-website.mjs", "test:api": "node scripts/check-public-api.mjs", "test:size": "node scripts/check-bundle-size.mjs", - "test:package": "npm run build:dist && node --test test/package/verify-package.test.mjs", + "test:package": "npm run build:dist && node --test test/package/foundation.test.mjs test/package/verify-package.test.mjs", "test:workflows": "node --test scripts/verify-workflows.test.mjs", "test:clean-check": "node --test scripts/verify-clean-check.test.mjs", "release:check": "node scripts/verify-release.mjs", diff --git a/scripts/verify-package.mjs b/scripts/verify-package.mjs index c6156cd..35e4214 100644 --- a/scripts/verify-package.mjs +++ b/scripts/verify-package.mjs @@ -130,6 +130,10 @@ try { ...installPackages, ], consumer, + { + NPM_CONFIG_ALLOW_SCRIPTS: undefined, + npm_config_allow_scripts: undefined, + }, ) const installedPackage = JSON.parse( @@ -258,15 +262,21 @@ function validatePackedFiles(files) { ) } -function run(command, args, cwd = repositoryRoot) { +function run(command, args, cwd = repositoryRoot, environmentOverrides = {}) { + const environment = { + ...process.env, + npm_config_audit: 'false', + npm_config_fund: 'false', + npm_config_update_notifier: 'false', + ...environmentOverrides, + } + for (const [name, value] of Object.entries(environment)) { + if (value === undefined) delete environment[name] + } + return execFileAsync(command, args, { cwd, - env: { - ...process.env, - npm_config_audit: 'false', - npm_config_fund: 'false', - npm_config_update_notifier: 'false', - }, + env: environment, maxBuffer: 10 * 1024 * 1024, }) } @@ -316,6 +326,14 @@ async function validateSourceDocumentation() { /^## \[0\.1\.0-alpha\.0\] - \d{4}-\d{2}-\d{2}$/m, 'CHANGELOG.md must contain the dated 0.1.0-alpha.0 section', ) + assert.match( + changelog, + new RegExp( + `^## \\[${escapeRegExp(packageJson.version)}\\] - \\d{4}-\\d{2}-\\d{2}$`, + 'm', + ), + `CHANGELOG.md must contain a dated ${packageJson.version} section`, + ) const contributing = files.get('CONTRIBUTING.md') assert.ok(contributing, 'CONTRIBUTING.md must be readable') @@ -442,6 +460,10 @@ function typescriptBlocks(source) { ) } +function escapeRegExp(value) { + return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') +} + async function pathExists(target) { try { await access(target) diff --git a/scripts/verify-release.mjs b/scripts/verify-release.mjs index cd7507f..ecbfdea 100644 --- a/scripts/verify-release.mjs +++ b/scripts/verify-release.mjs @@ -21,8 +21,7 @@ const repositoryRoot = path.resolve(import.meta.dirname, '..') const expectedName = '@nipe-solutions/react-swipe-actions' const expectedRepository = 'https://github.com/NIPE-Solutions/react-swipe-actions' -const semverPrerelease = - /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*)(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/ +const semverStable = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/ export function validateReleaseMetadata(packageJson, changelog) { assert.equal(packageJson.name, expectedName, 'Unexpected package name') @@ -32,15 +31,12 @@ export function validateReleaseMetadata(packageJson, changelog) { 'Unexpected package repository', ) - const match = semverPrerelease.exec(packageJson.version) + const match = semverStable.exec(packageJson.version) assert.ok( match, - `Package version ${packageJson.version} must be a semantic prerelease`, + `Package version ${packageJson.version} must be a stable semantic version`, ) - const channel = match[4].split('.')[0] - if (match[1] === '0' && match[2] === '1') { - assert.equal(channel, 'alpha', '0.1 prereleases must use the alpha channel') - } + const channel = 'latest' assert.match( changelog, new RegExp( @@ -62,7 +58,7 @@ export function validateReleaseMetadata(packageJson, changelog) { assert.equal( packageJson.publishConfig?.tag, channel, - `publishConfig dist-tag must match prerelease channel ${channel}`, + `publishConfig dist-tag must be ${channel}`, ) return { name: packageJson.name, version: packageJson.version, channel } @@ -231,7 +227,7 @@ export async function verifyRelease({ dryRun = false, outputDirectory } = {}) { for (const message of contextMessages) console.log(message) console.log(`Release candidate: ${release.name}@${release.version}`) - console.log(`Prerelease channel: ${release.channel}`) + console.log(`Release channel: ${release.channel}`) await runVisible('npm', ['run', 'build:dist']) await runVisible('npm', ['run', 'test:size']) diff --git a/scripts/verify-website-static.mjs b/scripts/verify-website-static.mjs index 6f7e3cf..276d08b 100644 --- a/scripts/verify-website-static.mjs +++ b/scripts/verify-website-static.mjs @@ -192,7 +192,7 @@ async function verifyIdentityAndMetadata() { await readFile(path.join(repositoryRoot, 'package.json'), 'utf8'), ) assert.equal(siteMetadata.version, packageJson.version) - assert.equal(siteMetadata.statusLabel, '0.1 alpha') + assert.equal(siteMetadata.statusLabel, '1.0 stable') assert.equal(siteMetadata.reactCompatibility, 'React 18.3 and 19') const mainSource = await readFile(path.join(sourceRoot, 'main.tsx'), 'utf8') diff --git a/scripts/verify-website.mjs b/scripts/verify-website.mjs index 0706ab4..eb7368c 100644 --- a/scripts/verify-website.mjs +++ b/scripts/verify-website.mjs @@ -150,8 +150,8 @@ try { ) assert.equal( (await page.locator('.status-line small').textContent())?.trim(), - '0.1 alpha', - 'The package prerelease status is visible beside the hero identity', + '1.0 stable', + 'The stable package status is visible beside the hero identity', ) assert.equal( await page.locator('.site-footer__links a').count(), diff --git a/scripts/verify-workflows.test.mjs b/scripts/verify-workflows.test.mjs index bd61e4e..a6cf8c5 100644 --- a/scripts/verify-workflows.test.mjs +++ b/scripts/verify-workflows.test.mjs @@ -130,7 +130,7 @@ function validateReleaseWorkflow(workflow) { assert.equal(workflow.on.workflow_dispatch.inputs.confirm.required, true) assert.equal( workflow.concurrency.group, - 'npm-nipe-solutions-react-swipe-actions-alpha', + 'npm-nipe-solutions-react-swipe-actions-stable', ) assert.doesNotMatch(workflow.concurrency.group, /github\.(ref|sha)/) assert.equal(workflow.concurrency['cancel-in-progress'], false) @@ -188,7 +188,7 @@ function validateReleaseWorkflow(workflow) { stepsFor(verify).indexOf(uploadStep) > stepsFor(verify).indexOf(releaseStep), ) - assert.equal(uploadStep.with.name, 'npm-package-alpha') + assert.equal(uploadStep.with.name, 'npm-package-stable') assert.equal(uploadStep.with.path, 'release-artifact') assert.equal(uploadStep.with['if-no-files-found'], 'error') assert.ok(uploadStep.with['retention-days'] <= 3) @@ -209,7 +209,7 @@ function validateReleaseWorkflow(workflow) { const downloadStep = publishSteps.find((step) => step.uses?.startsWith('actions/download-artifact@'), ) - assert.equal(downloadStep?.with?.name, 'npm-package-alpha') + assert.equal(downloadStep?.with?.name, 'npm-package-stable') assert.equal(downloadStep?.with?.path, 'release-artifact') const protectedStep = publishSteps.at(-1) @@ -228,7 +228,7 @@ function validateReleaseWorkflow(workflow) { /\$\{\{[^}]*needs\.[^}]*outputs/, 'OIDC shell must not interpolate job outputs directly', ) - assert.match(protectedStep.run, /RELEASE_CHANNEL.*alpha/) + assert.match(protectedStep.run, /RELEASE_CHANNEL.*latest/) assert.ok(protectedStep.run.includes(releaseTarball)) assert.match(protectedStep.run, /\^\[A-Za-z0-9\._-\]\+\$/) assert.match(protectedStep.run, /exactly one entry/) @@ -401,7 +401,7 @@ test('release policy rejects ref-scoped publication concurrency', async () => { assert.throws( () => validateReleaseWorkflow(workflow), - /npm-nipe-solutions-react-swipe-actions-alpha/, + /npm-nipe-solutions-react-swipe-actions-stable/, ) }) @@ -433,46 +433,39 @@ test('Dependabot updates npm and Actions monthly with grouped non-majors', async }) }) -test('release metadata requires the approved prerelease identity and provenance', async () => { +test('release metadata requires a stable version and provenance', async () => { const { validateReleaseMetadata } = await import('./verify-release.mjs') const packageJson = { name: '@nipe-solutions/react-swipe-actions', - version: '0.1.0-alpha.0', + version: '1.0.0', repository: { type: 'git', url: 'https://github.com/NIPE-Solutions/react-swipe-actions', }, - publishConfig: { access: 'public', provenance: true, tag: 'alpha' }, + publishConfig: { access: 'public', provenance: true, tag: 'latest' }, } - const changelog = '# Changelog\n\n## [0.1.0-alpha.0] - 2026-09-05\n' + const changelog = '# Changelog\n\n## [1.0.0] - 2026-09-29\n' assert.deepEqual(validateReleaseMetadata(packageJson, changelog), { name: '@nipe-solutions/react-swipe-actions', - version: '0.1.0-alpha.0', - channel: 'alpha', + version: '1.0.0', + channel: 'latest', }) assert.throws( () => validateReleaseMetadata( packageJson, - '# Changelog\n\n## [0.1.0-alpha.0] - Unreleased\n', + '# Changelog\n\n## [1.0.0] - Unreleased\n', ), /dated release entry/, ) - assert.throws( - () => - validateReleaseMetadata({ ...packageJson, version: '0.1.0' }, changelog), - /must be a semantic prerelease/, - ) - assert.throws( - () => - validateReleaseMetadata( - { ...packageJson, version: '0.1.0-alpha.01' }, - changelog, - ), - /must be a semantic prerelease/, - ) + for (const version of ['1.0.0-rc.1', '1.0.0+build.1', '01.0.0']) { + assert.throws( + () => validateReleaseMetadata({ ...packageJson, version }, changelog), + /must be a stable semantic version/, + ) + } assert.throws( () => validateReleaseMetadata( @@ -486,27 +479,15 @@ test('release metadata requires the approved prerelease identity and provenance' validateReleaseMetadata( { ...packageJson, - publishConfig: { ...packageJson.publishConfig, tag: 'latest' }, - }, - changelog, - ), - /dist-tag.*alpha/, - ) - assert.throws( - () => - validateReleaseMetadata( - { - ...packageJson, - version: '0.1.0-beta.0', publishConfig: { ...packageJson.publishConfig, tag: 'beta' }, }, - '# Changelog\n\n## [0.1.0-beta.0] - 2026-09-05\n', + changelog, ), - /0\.1 prereleases must use the alpha channel/, + /dist-tag.*latest/, ) assert.throws( () => validateReleaseMetadata(packageJson, '# Changelog\n'), - /CHANGELOG\.md.*0\.1\.0-alpha\.0/, + /CHANGELOG\.md.*1\.0\.0/, ) }) @@ -643,7 +624,7 @@ test('protected release shell treats output mutation payloads only as data', asy env: { ...process.env, RELEASE_TARBALL: payload, - RELEASE_CHANNEL: 'alpha', + RELEASE_CHANNEL: 'latest', }, }), (error) => { @@ -660,11 +641,11 @@ test('protected release shell treats output mutation payloads only as data', asy env: { ...process.env, RELEASE_TARBALL: releaseTarball, - RELEASE_CHANNEL: 'alpha\n$(touch injection-ran)', + RELEASE_CHANNEL: 'latest\n$(touch injection-ran)', }, }), (error) => { - assert.match(error.stderr, /release channel must be alpha/i) + assert.match(error.stderr, /release channel must be latest/i) return true }, ) @@ -697,7 +678,7 @@ test('protected release shell rejects extra or mismatched checksum entries', asy env: { ...process.env, RELEASE_TARBALL: tarball, - RELEASE_CHANNEL: 'alpha', + RELEASE_CHANNEL: 'latest', }, }), (error) => { @@ -713,7 +694,7 @@ test('protected release shell rejects extra or mismatched checksum entries', asy env: { ...process.env, RELEASE_TARBALL: tarball, - RELEASE_CHANNEL: 'alpha', + RELEASE_CHANNEL: 'latest', }, }), (error) => { diff --git a/test/package/foundation.test.mjs b/test/package/foundation.test.mjs index 1b20b72..e892a55 100644 --- a/test/package/foundation.test.mjs +++ b/test/package/foundation.test.mjs @@ -5,7 +5,7 @@ import test from 'node:test' test('package metadata has the approved identity and dependency policy', async () => { const pkg = JSON.parse(await readFile('package.json', 'utf8')) assert.equal(pkg.name, '@nipe-solutions/react-swipe-actions') - assert.equal(pkg.version, '0.1.0-alpha.1') + assert.equal(pkg.version, '1.0.0') assert.equal(pkg.type, 'module') assert.deepEqual(pkg.peerDependencies, { react: '^18.3.0 || ^19.0.0', diff --git a/test/package/verify-package.test.mjs b/test/package/verify-package.test.mjs index 0446c33..d4de375 100644 --- a/test/package/verify-package.test.mjs +++ b/test/package/verify-package.test.mjs @@ -169,18 +169,34 @@ test('packed file allowlist rejects an unexpected dist file', async () => { } }) -test('packed package passes isolated React 18 and React 19 consumers', async () => { - const { stdout, stderr } = await execFileAsync( - process.execPath, - ['scripts/verify-package.mjs'], - { - cwd: repositoryRoot, - maxBuffer: 10 * 1024 * 1024, - }, - ) +test('packed consumers ignore unrelated npm script policy', async () => { + const directory = await mkdtemp(path.join(tmpdir(), 'swipe-actions-npm-')) + const userConfig = path.join(directory, 'npmrc') - assert.equal(stderr, '') - assert.match(stdout, /React 18\.3\.1: ESM, CJS, types, SSR passed/) - assert.match(stdout, /React 19\.2\.8: ESM, CJS, types, SSR, and Vite passed/) - assert.match(stdout, /Packed package verification passed/) + try { + await writeFile(userConfig, 'allow-scripts=@example/unrelated-tool\n') + const { stdout, stderr } = await execFileAsync( + process.execPath, + ['scripts/verify-package.mjs'], + { + cwd: repositoryRoot, + env: { + ...process.env, + NPM_CONFIG_USERCONFIG: userConfig, + npm_config_allow_scripts: '@example/unrelated-tool', + }, + maxBuffer: 10 * 1024 * 1024, + }, + ) + + assert.equal(stderr, '') + assert.match(stdout, /React 18\.3\.1: ESM, CJS, types, SSR passed/) + assert.match( + stdout, + /React 19\.2\.8: ESM, CJS, types, SSR, and Vite passed/, + ) + assert.match(stdout, /Packed package verification passed/) + } finally { + await rm(directory, { recursive: true, force: true }) + } }) diff --git a/website/src/main.tsx b/website/src/main.tsx index a4744ee..98fcf4e 100644 --- a/website/src/main.tsx +++ b/website/src/main.tsx @@ -560,7 +560,7 @@ function Website() {
Can roots be nested?

- No. Nested swipe roots are outside the alpha contract and may + No. Nested swipe roots are outside the package contract and may compete for a pointer.