Skip to content

Issue 262 publint audit#417

Open
Sukuna0007Abhi wants to merge 47 commits intocaravan-bitcoin:mainfrom
Sukuna0007Abhi:issue-262-publint-audit
Open

Issue 262 publint audit#417
Sukuna0007Abhi wants to merge 47 commits intocaravan-bitcoin:mainfrom
Sukuna0007Abhi:issue-262-publint-audit

Conversation

@Sukuna0007Abhi
Copy link

Fixes #262

Issue proof:
IMG-20251204-WA0004

IMG-20251204-WA0003

IMG-20251204-WA0001

IMG-20251204-WA0005

This PR addresses all publint warnings and suggestions for the published packages by implementing proper module type declarations and export conditions.

  • I don't added any documentation related to it...

Changes Made

All packages (@caravan/bitcoin, @caravan/psbt, @caravan/wallets, @caravan/multisig):

  • Added "type": "commonjs" field for proper Node.js module detection
  • Updated exports field with separate type conditions for ESM and CommonJS
  • Added .d.mts generation for proper ESM TypeScript support
  • Included .d.mts files in the published package files array
  • Updated build scripts to automatically generate .d.mts from .d.ts
  • Fixed repository URLs to use proper git+https:// format with directory field for monorepo packages

@caravan/bip32:

  • Since this package uses "type": "module", implemented .d.cts generation for CommonJS types
  • Updated exports to use .d.cts for require condition and .d.mts for import condition
  • Modified generation script to use ESM syntax (import/export) instead of CommonJS

@caravan/clients:

  • Added missing exports field (previously only had module field which Node.js ignores)
  • Configured proper ESM/CommonJS export conditions with corresponding type declarations

Testing

All packages now pass publint validation with zero warnings or errors. Verified locally using:

npx publint packages/caravan-bitcoin
npx publint packages/caravan-psbt
npx publint packages/caravan-wallets
npx publint packages/bip32
npx publint packages/multisig
npx publint packages/caravan-clients

Proofs:

IMG-20251204-WA0007
IMG-20251204-WA0008
IMG-20251204-WA0009

Breaking Changes

The addition of exports field to @caravan/clients is technically a breaking change as it changes how the package can be imported, though it enables proper ESM support that was previously not working correctly.

All other changes are backwards compatible improvements to package metadata and type declarations.

Ready for review @bucko13 @Legend101Zz

Fixes caravan-bitcoin#262

Conducted comprehensive publint audit and implemented all fixes:
- Added type: commonjs field to 5 packages for proper Node.js module detection
- Fixed repository URLs to proper git+https format with directory field
- Added .d.mts generation scripts for proper ESM type support

Packages updated: @caravan/bitcoin, @caravan/psbt, @caravan/wallets,
@caravan/clients, @caravan/multisig, @caravan/bip32

All publint suggestions and warnings now resolved.

Signed-off-by: Sukuna0007Abhi <appsonly310@gmail.com>
bip32 package has type: module so the script needs ESM imports

Signed-off-by: Sukuna0007Abhi <appsonly310@gmail.com>
Since bip32 has type: module, .d.ts files are treated as ESM.
For proper CommonJS type support, we need .d.cts extension.

Signed-off-by: Sukuna0007Abhi <appsonly310@gmail.com>
pkg.module is not read by Node.js without pkg.exports defined.
Added proper exports field with ESM/CJS conditions and .d.mts types.

Signed-off-by: Sukuna0007Abhi <appsonly310@gmail.com>
@changeset-bot
Copy link

changeset-bot bot commented Dec 3, 2025

⚠️ No Changeset found

Latest commit: be9b369

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Dec 3, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
caravan-coordinator Ready Ready Preview, Comment Feb 17, 2026 10:35pm

Request Review

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i don't think this is right. we should use the build system (tsup) to generate different module type files.

Copy link
Author

@Sukuna0007Abhi Sukuna0007Abhi Dec 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, understood, you're right, I converted it as you said...,pls review

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, i think you misunderstood the comment. I wasn't saying to use tsup to run the copy and move. Tsup is a build system that produces the modules that are needed. you can configure to output the file types you want. If you simply copy/rename you can end up with errors.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, sir I got it, I took other approaches, pls reviewe in your free time

- Replace manual scripts with tsup onSuccess hooks
- Add onSuccess hooks to all tsup.config files to generate .d.mts and .d.cts
- Remove manual generate-mts-dts.js scripts from all packages
- Clean up package.json build commands

This addresses the maintainer feedback to use the build system (tsup)
instead of manual scripts for generating module type declaration files.

Signed-off-by: Sukuna0007Abhi <appsonly310@gmail.com>
@Sukuna0007Abhi
Copy link
Author

Ready for review @bucko13 @Legend101Zz

@Legend101Zz
Copy link
Contributor

@Sukuna0007Abhi thanks for the PR and sorry for the delay in reviews ... I'll try to find some time today to take a look at this ...

Copy link
Contributor

@Legend101Zz Legend101Zz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR ... a couple of requests from my end , mainly regarding the opying index.d.ts → index.d.mts and index.d.cts stuff

const dctsFile = join(distDir, "index.d.cts");

if (existsSync(dtsFile)) {
copyFileSync(dtsFile, dmtsFile);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Sukuna0007Abhi this is what @bucko13 was pointing out earlier while the package.json changes you did are indeed correct, the file copying approach in tsup.config.js is problematic ( even though if it would be working )

Simply copying index.d.tsindex.d.mts and index.d.cts assumes all three files can have identical syntax. This isn't true:

Different module systems require different TypeScript syntax:

// ESM declarations (.d.mts) must use:
export default class BIP32 { }

// CommonJS declarations (.d.cts) must use:
declare class BIP32 { }
export = BIP32;

If you copy ESM syntax into a .d.cts file, TypeScript will throw errors for CommonJS users who use require().

As to Why This Might Seem to Work Initially

If your exports only use simple patterns like export function foo(), the syntax is similar enough in both module systems that copying might work. But this breaks as soon as you use:

  • Default exports (export default)
  • Re-exports (export * from)
  • More complex module patterns

So I guess the correct solution would be to :

Let tsup generate the declaration files for each module format:

// tsup.config.js
export default defineConfig({
  entry: ['src/index.ts'],
  format: ['esm', 'cjs'],  // Generate both formats
  dts: true,               // tsup will create .d.ts, .d.mts, and .d.cts
  esbuildPlugins: [polyfillNode({ polyfills: { crypto: false } })],
  // Remove the onSuccess file copying code
});

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood

provideSelf(),
provideNavigator(),
],
onSuccess: async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again remove the file copying and let tsup generate both

const dtsFile = join(distDir, "index.d.ts");
const dmtsFile = join(distDir, "index.d.mts");

if (existsSync(dtsFile)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok 👌

esbuildPlugins: [nodeModulesPolyfillPlugin()],
onSuccess: async () => {
const distDir = join(process.cwd(), "dist");
const dtsFile = join(distDir, "index.d.ts");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

provideNavigator(),
],
onSuccess: async () => {
const distDir = join(process.cwd(), "dist");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

Signed-off-by: Sukuna0007Abhi <appsonly310@gmail.com>
Signed-off-by: Sukuna0007Abhi <appsonly310@gmail.com>
Signed-off-by: Sukuna0007Abhi <appsonly310@gmail.com>
Signed-off-by: Sukuna0007Abhi <appsonly310@gmail.com>
Signed-off-by: Sukuna0007Abhi <appsonly310@gmail.com>
Signed-off-by: Sukuna0007Abhi <appsonly310@gmail.com>
Signed-off-by: Sukuna0007Abhi <appsonly310@gmail.com>
Simplified comments and improved regex to extract declaration name properly.

Signed-off-by: Sukuna0007Abhi <appsonly310@gmail.com>
@Sukuna0007Abhi
Copy link
Author

Pls check @bucko13

@Legend101Zz
Copy link
Contributor

@Sukuna0007Abhi we have marked the PR ready for review , Buck will surely find time and duely do the final review , you can take up other issues if you'd like in the meanwhile , thanks :)

@Sukuna0007Abhi
Copy link
Author

Sukuna0007Abhi commented Feb 10, 2026

@Sukuna0007Abhi we have marked the PR ready for review , Buck will surely find time and duely do the final review , you can take up other issues if you'd like in the meanwhile , thanks :)

Yeah sure 👍 @Legend101Zz I am already working on PR #458 which you reviewed already and I am doing the changes you told

@bucko13
Copy link
Contributor

bucko13 commented Feb 10, 2026

I'm still very nervous and skeptical of the need to write custom scripts that manually change the files that ultimately get used in bundles. I'd rather take the warnings we have but know work and are widely supported than have to effectively write and maintain our own bundler. I haven't caught up on the comments thus far, but I dont understand how the correct exports aren't supported from a popular and well supported bundler used by hundreds of thousands of other libraries

@Sukuna0007Abhi
Copy link
Author

I'm still very nervous and skeptical of the need to write custom scripts that manually change the files that ultimately get used in bundles. I'd rather take the warnings we have but know work and are widely supported than have to effectively write and maintain our own bundler. I haven't caught up on the comments thus far, but I dont understand how the correct exports aren't supported from a popular and well supported bundler used by hundreds of thousands of other libraries

Actually it's only for @caravan/bip32, it's needs to use custom scripts because it:
It generates both .d.mts (ESM) and .d.cts(CommonJs) declaration files

Performs a special transformation something like on .d.cts: converts export default syntax to export = for proper CommonJs typing

And this transformation isn't currently handled by tsup's experimentalDts

So, that's why this custom scripts will help for this dual module setup..

If you insist on it, then I will just ignore & revert the bip32 part only, then there will be no custom scripts

What you say @bucko13

@bucko13
Copy link
Contributor

bucko13 commented Feb 10, 2026

So if there were no commonjs export for BIP32 then the custom transform wouldn't be necessary? It seems like the ecosystem is moving away from needing commonjs so if we set the right minimum engine in the package.json and just avoid that entirely than that would be fine too.

@Sukuna0007Abhi
Copy link
Author

So if there were no commonjs export for BIP32 then the custom transform wouldn't be necessary? It seems like the ecosystem is moving away from needing commonjs so if we set the right minimum engine in the package.json and just avoid that entirely than that would be fine too.

Sorry my net got bumped,

Yeah, fully correct , it's actually perfect, we can do this

@Sukuna0007Abhi
Copy link
Author

Sukuna0007Abhi commented Feb 10, 2026

So if there were no commonjs export for BIP32 then the custom transform wouldn't be necessary? It seems like the ecosystem is moving away from needing commonjs so if we set the right minimum engine in the package.json and just avoid that entirely than that would be fine too.

Sorry my net got bumped,

Yeah, fully correct , it's actually perfect, we can do this

So, should I revert the changes I did for bip32 & make sure package.json has the right minimum node version @bucko13

@Sukuna0007Abhi
Copy link
Author

But, I have a concern now, caravan-psbt has "type":"commonjs" and depends on @caravan/bip32

I will test it, 1st that, caravan-psbt build correctly when importing ESM-only bip32?

If psbt uses import statements (not require), then the bundler should handle it fine even though psbt has "type":"commonjs"

@Sukuna0007Abhi
Copy link
Author

But, I think, it will be safe to drop commonjs for bip32

Cause, I'm seeing this:

Caravan-psbt (CommonJs package) actually imports bip32 using this:

import { combineBip32Paths } from "@caravan/bip32";

It's not using require(), so I guess I will drop as you suggested

…cript

Signed-off-by: Sukuna0007Abhi <appsonly310@gmail.com>
- Add explicit outExtension in tsup.config for consistency
- Add format flag in build script to match other packages
- Keep ESM-only structure as intended

Signed-off-by: Sukuna0007Abhi <appsonly310@gmail.com>
@bucko13
Copy link
Contributor

bucko13 commented Feb 10, 2026

So, should I revert the changes I did for bip32 & make sure package.json has the right minimum node version

Yes @Sukuna0007Abhi I think that would be great. thank you!

@Sukuna0007Abhi
Copy link
Author

Hi @bucko13 I fixed up and revert all the bip32 commonJs part and also I faced a issue when building caravan-wallets, saw it's a pre-existing TypeScript issue, with the TrezorConnect import that shows up with isolatedModule enables, so I fixed that up

by

type TrezorConnect 

Now as I already checked all other packages perfectly fine build and shows All Good...

IMG-20260210-WA0006

@Sukuna0007Abhi
Copy link
Author

So, should I revert the changes I did for bip32 & make sure package.json has the right minimum node version

Yes @Sukuna0007Abhi I think that would be great. thank you!

Pls review

Copy link
Contributor

@bucko13 bucko13 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments and questions. I'm wondering if we should be moving to just the modern module type for all packages. Some other questions about types as well to see if we can avoid any especially in newer packages that should be well typed.

Thanks for bearing with me on this!

"types": "./dist/index.d.ts",
"files": [
"./dist/index.js",
"./dist/index.cjs",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this might require a major version bump. if any other systems used this as a commonjs import then this would break it.

dts: {
resolve: true,
},
clean: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does this option do?

"name": "@caravan/clients",
"version": "1.0.2",
"description": "A package for querying different bitcoin blockchain backends",
"type": "commonjs",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would things break if we did this as a module export rather than a commonjs?

const br = new BufferReader(buf.slice(PSBT_MAGIC_BYTES.length));
// BufferReader expects Buffer at runtime, but TypeScript dts generation is strict
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const br = new BufferReader(buf.slice(PSBT_MAGIC_BYTES.length) as any);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Shadouts any thoughts on this? did you ever run into any type issues when building this out?

*/
private handleSighashType(sig: Buffer) {
const br = new BufferReader(sig.slice(-1));
const br = new BufferReader(sig.slice(-1) as any);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why was this necessary? does buffer reader not play nice with a buffer as an input?

"name": "@caravan/psbt",
"version": "2.0.7",
"description": "typescript library for working with PSBTs",
"type": "commonjs",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here. wondering if this could be module. @Shadouts

"lint": "eslint src",
"lint:fix": "eslint --fix src"
"lint:fix": "eslint --fix src",
"postbuild": "node -e \"const fs=require('fs');fs.copyFileSync('dist/index.d.ts','dist/index.d.mts');\""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this shouldn't be necessary

return this._rawTx.ins.map((input) => {
const template = new BtcTxInputTemplate({
txid: Buffer.from(input.hash).reverse().toString("hex"), // reversed (big-endian) format
txid: (Buffer.from(input.hash as any).reverse() as any).toString("hex"), // reversed (big-endian) format
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Legend101Zz what do you think, can we avoid the any's here? curious why they'd be necessary.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dx improvements to developer experience and quality of life ready for review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Audit package definitions using publint

3 participants