Skip to content

build: make every package publishable, released as @398ja/nap-* at 0.12.0 - #50

Merged
tcheeric merged 4 commits into
masterfrom
build/publishable-packages
Oct 8, 2026
Merged

tcheeric merged 4 commits into
masterfrom
build/publishable-packages

Conversation

@tcheeric

@tcheeric tcheeric commented Oct 8, 2026

Copy link
Copy Markdown
Owner

What

Makes all ten @imani/nap-* packages publishable to npm and bumps them to 0.12.0. Nothing is published by this PR. Prepared for 398ja/imani-wallet#212, where the wallet build needs a ../nap sibling checkout.

  • Build. npm run build compiles every package with tsc to ESM plus .d.ts in packages/*/dist, in dependency order (scripts/build.mjs, tsconfig.build.base.json, and one tsconfig.build.json per package).
  • Manifests. Every package now has exports (types/import/default pointing at dist/), main, module, types, files: ["dist"], sideEffects: false, publishConfig.access: public, plus repository, homepage and bugs.
  • Peers. nostr-tools is a peer of nap-core, nap-server, nap-client-http, nap-client-web and nap-client-nip46. @noble/hashes is a peer of nap-core (^1.8.0 || ^2.0.0) and nap-voucher. @noble/curves is a peer of nap-voucher. react is a peer of nap-react, which never declared it before. The wallet therefore gets one copy of each.
  • Ranges. Sibling dependencies are ^0.12.0, not exact pins or workspace links.
  • Source in the workspace. A nap-source export condition points at src/. The root tsconfig.json (customConditions), vitest.config.ts, the two tsc-driven tests and the example app all select it, so npm test and npm run typecheck never need a build. The condition is stripped from the published manifest.
  • Release. npm run release (scripts/release.mjs) typechecks, tests, builds, stages each package into .release/ and publishes in dependency order. --dry-run runs npm publish --dry-run for each package. --pack writes the tarballs with no credentials. A real release refuses to run without npm whoami or from a dirty tree, and resumes past versions already published.
  • Scope is one variable. NAP_SCOPE defaults to @398ja. The code keeps importing @imani/nap-*. Published sibling dependencies are written as npm aliases, e.g. "@imani/nap-core": "npm:@398ja/nap-core@^0.12.0", so the compiled JS needs no rewrite. NAP_SCOPE=@imani publishes plain @imani/nap-* if that org is ever confirmed. See RELEASING.md.
  • Browser safety. nap-core, nap-client-http, nap-client-web, nap-client-nip46 and nap-react must not import Node built-ins. scripts/publishing.test.ts (part of npm test) asserts this on source, and release staging re-checks the compiled dist/. Only nap-server imports node:crypto, and it is not a browser package.
  • Small fixes found on the way. The adapters now declare @imani/nap-core, which they import. nap-core imports @noble/hashes/sha2.js (exported by both 1.x and 2.x) instead of sha256 (1.x only).
  • CI gains a Build and pack step. Docs updated: README, CLAUDE.md, integration guide §0.6/§4/§11.4, tutorial 01, UPGRADING and CHANGELOG [0.12.0].

Not included: feat/nonce-free-voucher-signature (77c4306, nap-voucher canonical bytes). It is unmerged and has no PR. This branch is cut from master (e07a586).

Verification

npm ci && npm run typecheck && npm test
  Test Files 54 passed (54)   Tests 782 passed | 15 skipped (797)   (was 740 + 42 new contract tests)
npm run release:dry-run                     # typecheck + test + build + npm publish --dry-run x10
  dry run complete: @398ja/nap-core@0.12.0, @398ja/nap-server@0.12.0, @398ja/nap-adapter-express@0.12.0,
  @398ja/nap-adapter-fastify@0.12.0, @398ja/nap-client-http@0.12.0, @398ja/nap-client-web@0.12.0,
  @398ja/nap-client-nip46@0.12.0, @398ja/nap-react@0.12.0, @398ja/nap-store-postgres@0.12.0, @398ja/nap-voucher@0.12.0
NAP_SCOPE=@imani node scripts/release.mjs --dry-run --skip-checks   # also passes, plain names
node scripts/release.mjs --registry http://127.0.0.1:9 ...          # refuses: npm whoami failed
npm run release:pack (twice)                                         # byte-identical tarballs
python3 scripts/doccheck.py                                          # links 118/118, classes 191/191

End to end against a local Verdaccio, not npmjs: npm run release -- --registry http://localhost:4873 published all ten in order, and a rerun skipped all ten as already published. The wallet then installed from that registry (see the wallet PR). Plain Node import('@imani/nap-*') of every built package loads.

Publish order: nap-core, nap-server, nap-adapter-express, nap-adapter-fastify, nap-client-http, nap-client-web, nap-client-nip46, nap-react, nap-store-postgres, nap-voucher.

npm pack contents (scope @398ja)

Package Files Packed
nap-core package.json, README.md, dist/{base64,codec,errors,hash,header,index,types,url,validate}.{js,d.ts} 8.4 kB
nap-server package.json, README.md, dist/{acl,audience,guard,index,memory,metrics,rateLimit,server,types}.{js,d.ts} 34.0 kB
nap-adapter-express package.json, README.md, dist/{adapter,index}.{js,d.ts} 11.6 kB
nap-adapter-fastify package.json, README.md, dist/{adapter,index}.{js,d.ts} 11.6 kB
nap-client-http package.json, README.md, dist/{client,index}.{js,d.ts} 2.1 kB
nap-client-web package.json, README.md, dist/{activityLock,broadcast,httpClient,index,keyStore,nip07,reunlock,secretStore,session,signerCapabilities,signerPreference,signers,storage,types,webCryptoSecretStore}.{js,d.ts} 24.9 kB
nap-client-nip46 package.json, README.md, dist/{connection,errors,index,persistence,signer,timeout}.{js,d.ts} 9.8 kB
nap-react package.json, README.md, dist/{index,NapProvider,signingAccess,types,useNip07,useReunlock,useSignerPreference,useStoredConnection}.{js,d.ts} 22.5 kB
nap-store-postgres package.json, README.md, dist/index.{js,d.ts} 4.4 kB
nap-voucher package.json, README.md, dist/{allowlist,availability,dleq,index,mintClient,resolver,secret}.{js,d.ts} 32.0 kB

Published manifest, nap-client-web:

"exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js", "default": "./dist/index.js" }, "./package.json": "./package.json" },
"dependencies": {
  "@imani/nap-client-http": "npm:@398ja/nap-client-http@^0.12.0",
  "@imani/nap-core": "npm:@398ja/nap-core@^0.12.0"
},
"peerDependencies": { "nostr-tools": "^2.23.0", "typescript": ">=5.7" }

Before the first publish

  • Scope. The @imani org exists on npm, owned by a user named imani, with 0 packages. 398ja is not shown as a member. @398ja is the publishing account's own scope (it already holds nostr-chunked-events and nostr-app-storage), hence the default.
  • No LICENSE. The repo has none and the manifests declare no license. npm will publish the packages as unlicensed. The owner should decide on a license before or soon after the first publish.

Publish (owner, after merge, from the merge commit)

git checkout master && git pull && npm ci
npm whoami                      # must print 398ja (login, or a token in ~/.npmrc / NPM_CONFIG_USERCONFIG)
npm run release                 # NAP_SCOPE defaults to @398ja; typecheck, test, build, publish x10 in order

Refs 398ja/imani-wallet#212

tcheeric added 2 commits October 8, 2026 20:06
…12.0

Each package compiles to ESM + .d.ts in dist/ (tsc, dependency order) and its
manifest now carries exports/main/module/types pointing there, files: ["dist"],
sideEffects: false and publishConfig.access: public. A `nap-source` export
condition keeps the workspace typecheck, tests and example on src/; release
staging strips it.

nostr-tools, @noble/hashes, @noble/curves and react become peer dependencies so
a consumer gets one shared copy. Sibling deps are ^0.12.0 ranges. The adapters
declare nap-core, which they import. nap-core imports @noble/hashes/sha2.js,
the subpath both 1.x and 2.x export.

scripts/release.mjs typechecks, tests, builds and publishes in dependency order
(--dry-run, --pack). The registry scope is one setting, NAP_SCOPE (default
@398ja); sibling deps are written as npm aliases so @imani/nap-* import names
survive. scripts/publishing.test.ts pins the manifest contract and that the
browser packages import no Node built-in. CI now builds and packs.

Refs 398ja/imani-wallet#212
Critical advisory published after master's last green audit; master fails the
same production audit. Only the lockfile entry moves: npm update/audit fix
would also re-resolve express's qs below the 6.16.0 override.
@tcheeric

tcheeric commented Oct 8, 2026

Copy link
Copy Markdown
Owner Author

Added bb0ba84: proxy-addr 2.0.7 -> 2.0.8 in the lockfile for GHSA-jqcg-44mw-7w3h (critical, published after master's last green run; master fails the same npm audit --omit=dev). Edited the one lockfile entry rather than npm update/audit fix, which also re-resolve express's qs below the 6.16.0 override. CI now green on Node 20.19.0 and 22.x, including the new Build and pack step.

tcheeric added 2 commits October 8, 2026 22:05
Root LICENSE, "license": "MIT" in every manifest, and release staging copies
the LICENSE into each package so every tarball carries it.
@tcheeric
tcheeric merged commit 5e1be20 into master Oct 8, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant