@smartledger/bsv 6.2.2 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartledger/bsv",
3
- "version": "6.2.2",
3
+ "version": "7.0.0",
4
4
  "description": "🚀 Complete Bitcoin SV development framework with legally-recognizable DID:web + W3C VC-JWT toolkit, Legal Token Protocol (LTP), Global Digital Attestation Framework (GDAF), StatusList2021 revocation, and 16 flexible loading options. Standards-based credentials with ES256/ES256K support, on-chain BSV anchoring, and comprehensive Bitcoin SV API. Perfect for legal tokens, verifiable credentials, DeFi, smart contracts, and secure Bitcoin applications.",
5
5
  "author": "SmartLedger Technology <hello@smartledger.technology> (https://smartledger.technology)",
6
6
  "homepage": "https://github.com/codenlighten/smartledger-bsv#readme",
@@ -9,6 +9,19 @@
9
9
  },
10
10
  "main": "index.js",
11
11
  "types": "bsv.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./bsv.d.ts",
15
+ "import": "./index.mjs",
16
+ "require": "./index.js",
17
+ "default": "./index.js"
18
+ },
19
+ "./package.json": "./package.json",
20
+ "./version": "./version.js",
21
+ "./lib/*.js": "./lib/*.js",
22
+ "./lib/*": "./lib/*.js",
23
+ "./*": "./*"
24
+ },
12
25
  "engines": {
13
26
  "node": ">=20.19.0"
14
27
  },
@@ -51,7 +64,7 @@
51
64
  "preimage:extract": "node examples/preimage/extract_preimage_bidirectional.js",
52
65
  "prepublishOnly": "npm run build-all",
53
66
  "sync-cdn": "node scripts/sync-cdn-urls.js",
54
- "version": "node scripts/sync-cdn-urls.js && node scripts/sync-version.js && git add README.md docs version.js",
67
+ "version": "node scripts/sync-cdn-urls.js && node scripts/sync-version.js && node scripts/gen-esm-wrapper.js && git add README.md docs version.js index.mjs",
55
68
  "test:browser:ci": "node tests/browser-smoke-runner.js"
56
69
  },
57
70
  "unpkg": "bsv.min.js",
@@ -59,6 +72,7 @@
59
72
  "cdn": "bsv.min.js",
60
73
  "files": [
61
74
  "index.js",
75
+ "index.mjs",
62
76
  "version.js",
63
77
  "test/",
64
78
  ".mocharc.json",
@@ -0,0 +1,66 @@
1
+ 'use strict'
2
+
3
+ /* global describe, it */
4
+
5
+ // Guards index.mjs — the real ESM entry behind the package's `import` condition.
6
+ // Asserts (a) it hasn't drifted from the CJS surface, (b) native ESM default AND
7
+ // named imports actually work, and (c) deprecated getters (SmartUTXO) are NOT
8
+ // forced as named exports (they'd fire their warning on every import).
9
+ //
10
+ // ESM behaviour is exercised in a child process (via an --input-type=module
11
+ // script string) rather than a dynamic import() in this file, so the source
12
+ // stays parseable by the pinned standard@12 linter.
13
+
14
+ require('chai').should()
15
+ var fs = require('fs')
16
+ var path = require('path')
17
+ var execFileSync = require('child_process').execFileSync
18
+ var spawnSync = require('child_process').spawnSync
19
+ var gen = require('../../scripts/gen-esm-wrapper')
20
+
21
+ var ROOT = path.resolve(__dirname, '../..')
22
+ var MJS = path.join(ROOT, 'index.mjs')
23
+
24
+ function runEsm (body) {
25
+ return execFileSync(process.execPath, ['--input-type=module', '-e', body],
26
+ { cwd: ROOT, stdio: 'pipe' })
27
+ }
28
+
29
+ describe('ESM wrapper (index.mjs)', function () {
30
+ it('is in sync with the CJS surface (no drift)', function () {
31
+ var onDisk = fs.readFileSync(MJS, 'utf8')
32
+ onDisk.should.equal(gen.generate())
33
+ })
34
+
35
+ it('exports every non-accessor top-level member as a named binding', function () {
36
+ var bsv = require('../..')
37
+ var names = gen.exportableNames(bsv)
38
+ names.length.should.be.above(100)
39
+ // SmartUTXO is an accessor (deprecated getter) and must be excluded.
40
+ names.should.not.include('SmartUTXO')
41
+ Object.getOwnPropertyDescriptor(bsv, 'SmartUTXO').get.should.be.a('function')
42
+ })
43
+
44
+ it('resolves real ESM default + named imports natively', function () {
45
+ runEsm(
46
+ 'import bsv, { PrivateKey, crypto } from ' + JSON.stringify('./index.mjs') + ';' +
47
+ 'process.exit((bsv && typeof PrivateKey === "function" && ' +
48
+ 'PrivateKey === bsv.PrivateKey && typeof crypto.ECDSA === "function") ? 0 : 3)')
49
+ })
50
+
51
+ it('does not emit the SmartUTXO deprecation warning at import (getter excluded)', function () {
52
+ // Re-exporting the getter would trip its console.warn at import time; stderr
53
+ // must be empty for a bare `import './index.mjs'`.
54
+ var res = spawnSync(process.execPath,
55
+ ['--input-type=module', '-e', 'import ' + JSON.stringify('./index.mjs') + ';'],
56
+ { cwd: ROOT, encoding: 'utf8' })
57
+ res.status.should.equal(0)
58
+ res.stderr.should.equal('')
59
+ })
60
+
61
+ it('keeps deprecated getters reachable via the default export only', function () {
62
+ runEsm(
63
+ 'import bsv from ' + JSON.stringify('./index.mjs') + ';' +
64
+ 'process.exit(("SmartUTXO" in bsv) ? 0 : 3)')
65
+ })
66
+ })
@@ -0,0 +1,58 @@
1
+ 'use strict'
2
+
3
+ /* global describe, it */
4
+
5
+ // Guards the 7.0 package.json `exports` map. Adding `exports` switches Node to
6
+ // strict subpath resolution, so this asserts the surface consumers actually use
7
+ // still resolves (via package self-reference, which Node enables once `exports`
8
+ // exists): the main entry, package.json, ./version, the shipped bundles, and
9
+ // lib/* deep imports in BOTH extension styles. Also smoke-tests the ESM `import`
10
+ // condition in a child process so the dual-ready "." entry can't silently rot.
11
+
12
+ require('chai').should()
13
+ var path = require('path')
14
+ var execFileSync = require('child_process').execFileSync
15
+
16
+ var N = '@smartledger/bsv'
17
+ var ROOT = path.resolve(__dirname, '../..')
18
+
19
+ describe('7.0 exports map resolution', function () {
20
+ it('resolves the main entry via self-reference', function () {
21
+ var bsv = require(N)
22
+ bsv.should.be.an('object')
23
+ bsv.PrivateKey.should.be.a('function')
24
+ bsv.crypto.ECDSA.should.be.a('function')
25
+ })
26
+
27
+ it('exposes package.json and ./version, and they agree', function () {
28
+ var pkg = require(N + '/package.json')
29
+ var version = require(N + '/version')
30
+ pkg.name.should.equal(N)
31
+ version.should.equal(pkg.version)
32
+ })
33
+
34
+ it('resolves lib/* deep imports with and without the .js extension', function () {
35
+ var withExt = require(N + '/lib/crypto/ecdsa.js')
36
+ var noExt = require(N + '/lib/crypto/ecdsa')
37
+ withExt.should.be.a('function')
38
+ noExt.should.equal(withExt) // same module, one cache entry
39
+ })
40
+
41
+ it('serves the full browser bundle over a subpath (loaded in isolation)', function () {
42
+ // The bundle is a self-contained bsv; loading it in-process collides with the
43
+ // main require above ("multiple bsv instances"), so resolve+load it in a child.
44
+ var script = 'var m=require(' + JSON.stringify(N + '/bsv.min.js') + ');' +
45
+ 'process.exit(m && m.PrivateKey ? 0 : 3)'
46
+ execFileSync(process.execPath, ['-e', script], { cwd: ROOT, stdio: 'pipe' })
47
+ })
48
+
49
+ it('routes the ESM `import` condition to index.mjs with default AND named exports', function () {
50
+ // Proves the dual-ESM entry end-to-end through the package specifier: the
51
+ // `import` condition resolves to index.mjs, which exposes real named bindings.
52
+ var script =
53
+ 'import bsv, { PrivateKey, Transaction, crypto } from ' + JSON.stringify(N) + ';' +
54
+ 'process.exit((bsv && bsv.PrivateKey && PrivateKey === bsv.PrivateKey && ' +
55
+ 'typeof Transaction === "function" && typeof crypto.ECDSA === "function") ? 0 : 3)'
56
+ execFileSync(process.execPath, ['--input-type=module', '-e', script], { cwd: ROOT, stdio: 'pipe' })
57
+ })
58
+ })
@@ -176,7 +176,7 @@ describe('ECDSA', function () {
176
176
  it('should create a valid signature', function () {
177
177
  ecdsa.randomK()
178
178
  ecdsa.sign()
179
- ecdsa.verify().verified.should.equal(true)
179
+ ecdsa.verify().should.equal(true)
180
180
  })
181
181
 
182
182
  it('should should throw an error if hashbuf is not 32 bytes', function () {
@@ -253,11 +253,36 @@ describe('ECDSA', function () {
253
253
  it('should verify a signature that was just signed', function () {
254
254
  ecdsa.sig = Signature.fromString('3046022100e9915e6236695f093a4128ac2a956c' +
255
255
  '40ed971531de2f4f41ba05fac7e2bd019c02210094e6a4a769cc7f2a8ab3db696c7cd8d56bcdbfff860a8c81de4bc6a798b90827')
256
- ecdsa.verify().verified.should.equal(true)
256
+ ecdsa.verify().should.equal(true)
257
+ })
258
+ // 7.0: verify() returns a strict boolean, not the (always-truthy) instance.
259
+ // A forged signature must be REJECTED by `if (ecdsa.verify())`, which was the
260
+ // whole point of removing the trap.
261
+ it('returns a strict boolean, not the instance (7.0 trap closed)', function () {
262
+ ecdsa.signRandomK()
263
+ var result = ecdsa.verify()
264
+ result.should.be.a('boolean')
265
+ result.should.equal(true)
266
+ // Forge the signature: the return value itself must be falsy.
267
+ var forged = new ECDSA()
268
+ forged.hashbuf = ecdsa.hashbuf
269
+ forged.pubkey = ecdsa.pubkey
270
+ forged.sig = new Signature(ecdsa.sig.r.add(new BN(1)), ecdsa.sig.s)
271
+ forged.verify().should.equal(false)
272
+ ;(!!forged.verify()).should.equal(false) // `if (forged.verify())` does NOT enter
273
+ })
274
+ it('verifyBool() remains a strict-boolean alias', function () {
275
+ ecdsa.signRandomK()
276
+ ecdsa.verifyBool().should.equal(true)
277
+ var forged = new ECDSA()
278
+ forged.hashbuf = ecdsa.hashbuf
279
+ forged.pubkey = ecdsa.pubkey
280
+ forged.sig = new Signature(ecdsa.sig.r.add(new BN(1)), ecdsa.sig.s)
281
+ forged.verifyBool().should.equal(false)
257
282
  })
258
283
  it('should verify this known good signature', function () {
259
284
  ecdsa.signRandomK()
260
- ecdsa.verify().verified.should.equal(true)
285
+ ecdsa.verify().should.equal(true)
261
286
  })
262
287
  it('should verify a valid signature, and unverify an invalid signature', function () {
263
288
  var sig = ECDSA.sign(ecdsa.hashbuf, ecdsa.privkey)
@@ -295,7 +320,7 @@ describe('ECDSA', function () {
295
320
  ecdsa2.k.toString().should.equal(ecdsa.k.toString())
296
321
  ecdsa2.sig.toString().should.equal(ecdsa.sig.toString())
297
322
  ecdsa2.sig.i.should.equal(ecdsa.sig.i)
298
- ecdsa.verify().verified.should.equal(true)
323
+ ecdsa.verify().should.equal(true)
299
324
  })
300
325
  })
301
326
 
@@ -49,15 +49,19 @@ describe('security: fail-closed verification contracts', function () {
49
49
  inst(wrongPub).verifyBool().should.equal(false)
50
50
  })
51
51
 
52
- // Locks the documented trap: instance .verify() returns the INSTANCE (truthy), so it
53
- // must never be read as a boolean. If this ever changes (e.g. a deliberate 7.0 that
54
- // makes verify() return a bool), this test forces the change to be intentional.
55
- it('instance .verify() returns the instance with the result on .verified (documented trap)', function () {
56
- var e = new ECDSA(); e.hashbuf = hash; e.sig = goodSig; e.pubkey = wrongPub
57
- var r = e.verify()
58
- ;(typeof r).should.equal('object') // NOT a boolean — the trap
59
- isStrictBool(r.verified).should.equal(true)
60
- r.verified.should.equal(false) // forged → verified is false, even though `r` is truthy
52
+ // 7.0: the trap is CLOSED. Instance .verify() now returns a STRICT boolean, so
53
+ // `if (ecdsa.verify())` correctly rejects a forgery. (Pre-7.0 it returned the
54
+ // truthy instance with the real result on .verified; that idiom is gone.)
55
+ it('instance .verify() returns a strict boolean and fails closed on a forgery', function () {
56
+ var good = new ECDSA(); good.hashbuf = hash; good.sig = goodSig; good.pubkey = rightPub
57
+ isStrictBool(good.verify()).should.equal(true)
58
+ good.verify().should.equal(true)
59
+
60
+ var forged = new ECDSA(); forged.hashbuf = hash; forged.sig = goodSig; forged.pubkey = wrongPub
61
+ isStrictBool(forged.verify()).should.equal(true)
62
+ forged.verify().should.equal(false) // forged → false, and `if (forged.verify())` does NOT enter
63
+ // The result is still mirrored on .verified as a side effect.
64
+ forged.verified.should.equal(false)
61
65
  })
62
66
  })
63
67
 
package/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  'use strict'
2
2
  // GENERATED by scripts/sync-version.js on `npm version` — do not edit.
3
- module.exports = '6.2.2'
3
+ module.exports = '7.0.0'