@bsv/wallet-toolbox 1.5.19 → 1.5.21

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/docs/client.md +5 -2
  3. package/docs/wallet.md +5 -2
  4. package/mobile/out/src/WalletPermissionsManager.js +3 -3
  5. package/mobile/out/src/WalletPermissionsManager.js.map +1 -1
  6. package/mobile/out/src/sdk/validationHelpers.d.ts +5 -2
  7. package/mobile/out/src/sdk/validationHelpers.d.ts.map +1 -1
  8. package/mobile/out/src/sdk/validationHelpers.js +5 -2
  9. package/mobile/out/src/sdk/validationHelpers.js.map +1 -1
  10. package/mobile/out/src/storage/methods/listOutputsIdb.d.ts.map +1 -1
  11. package/mobile/out/src/storage/methods/listOutputsIdb.js +3 -0
  12. package/mobile/out/src/storage/methods/listOutputsIdb.js.map +1 -1
  13. package/mobile/package-lock.json +6 -6
  14. package/mobile/package.json +2 -2
  15. package/out/src/WalletPermissionsManager.js +3 -3
  16. package/out/src/WalletPermissionsManager.js.map +1 -1
  17. package/out/src/sdk/validationHelpers.d.ts +5 -2
  18. package/out/src/sdk/validationHelpers.d.ts.map +1 -1
  19. package/out/src/sdk/validationHelpers.js +5 -2
  20. package/out/src/sdk/validationHelpers.js.map +1 -1
  21. package/out/src/storage/methods/listOutputsIdb.d.ts.map +1 -1
  22. package/out/src/storage/methods/listOutputsIdb.js +3 -0
  23. package/out/src/storage/methods/listOutputsIdb.js.map +1 -1
  24. package/out/src/storage/methods/listOutputsKnex.d.ts.map +1 -1
  25. package/out/src/storage/methods/listOutputsKnex.js +12 -7
  26. package/out/src/storage/methods/listOutputsKnex.js.map +1 -1
  27. package/out/test/wallet/list/listOutputs.test.d.ts.map +1 -1
  28. package/out/test/wallet/list/listOutputs.test.js +70 -0
  29. package/out/test/wallet/list/listOutputs.test.js.map +1 -1
  30. package/out/tsconfig.all.tsbuildinfo +1 -1
  31. package/package.json +3 -3
  32. package/src/WalletPermissionsManager.ts +2 -2
  33. package/src/sdk/validationHelpers.ts +6 -3
  34. package/src/storage/methods/listOutputsIdb.ts +2 -1
  35. package/src/storage/methods/listOutputsKnex.ts +12 -7
  36. package/test/wallet/list/listOutputs.test.ts +73 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/wallet-toolbox",
3
- "version": "1.5.19",
3
+ "version": "1.5.21",
4
4
  "description": "BRC100 conforming wallet, wallet storage and wallet signer components",
5
5
  "main": "./out/src/index.js",
6
6
  "types": "./out/src/index.d.ts",
@@ -30,9 +30,9 @@
30
30
  },
31
31
  "homepage": "https://github.com/bsv-blockchain/wallet-toolbox#readme",
32
32
  "dependencies": {
33
- "@bsv/auth-express-middleware": "^1.2.2",
33
+ "@bsv/auth-express-middleware": "^1.2.3",
34
34
  "@bsv/payment-express-middleware": "^1.2.3",
35
- "@bsv/sdk": "^1.6.20",
35
+ "@bsv/sdk": "^1.6.23",
36
36
  "express": "^4.21.2",
37
37
  "idb": "^8.0.2",
38
38
  "knex": "^3.1.0",
@@ -1002,7 +1002,7 @@ export class WalletPermissionsManager implements WalletInterface {
1002
1002
  // We skip spending permission entirely
1003
1003
  return true
1004
1004
  }
1005
- const cacheKey = this.buildRequestKey({ type: 'spending', originator })
1005
+ const cacheKey = this.buildRequestKey({ type: 'spending', originator, spending: { satoshis } })
1006
1006
  if (this.isPermissionCached(cacheKey)) {
1007
1007
  return true
1008
1008
  }
@@ -2916,7 +2916,7 @@ export class WalletPermissionsManager implements WalletInterface {
2916
2916
  case 'certificate':
2917
2917
  return `cert:${r.originator}:${!!r.privileged}:${r.certificate?.verifier}:${r.certificate?.certType}:${r.certificate?.fields.join('|')}`
2918
2918
  case 'spending':
2919
- return `spend:${r.originator}`
2919
+ return `spend:${r.originator}:${r.spending?.satoshis}`
2920
2920
  }
2921
2921
  }
2922
2922
  }
@@ -881,7 +881,7 @@ export interface ValidListOutputsArgs extends ValidWalletSignerArgs {
881
881
  includeTags: BooleanDefaultFalse
882
882
  includeLabels: BooleanDefaultFalse
883
883
  limit: PositiveIntegerDefault10Max10000
884
- offset: PositiveIntegerOrZero
884
+ offset: number
885
885
  seekPermission: BooleanDefaultTrue
886
886
  knownTxids: string[]
887
887
  }
@@ -896,7 +896,10 @@ export interface ValidListOutputsArgs extends ValidWalletSignerArgs {
896
896
  * @param {BooleanDefaultFalse} [args.includeTags] - Optional. Whether the tags associated with the output should be returned.
897
897
  * @param {BooleanDefaultFalse} [args.includeLabels] - Optional. Whether the labels associated with the transaction containing the output should be returned.
898
898
  * @param {PositiveIntegerDefault10Max10000} [args.limit] - Optional limit on the number of outputs to return.
899
- * @param {PositiveIntegerOrZero} [args.offset] - Optional. Number of outputs to skip before starting to return results.
899
+ * @param {number} [args.offset] - If positive or zero: Number of outputs to skip before starting to return results, oldest first.
900
+ * If negative: Outputs are returned newest first and offset of -1 is the newest output.
901
+ * When using negative offsets, caution is required as new outputs may be added between calls,
902
+ * potentially causing outputs to be duplicated across calls.
900
903
  * @param {BooleanDefaultTrue} [args.seekPermission] — Optional. Whether to seek permission from the user for this operation if required. Default true, will return an error rather than proceed if set to false.
901
904
  */
902
905
  export function validateListOutputsArgs(args: ListOutputsArgs): ValidListOutputsArgs {
@@ -915,7 +918,7 @@ export function validateListOutputsArgs(args: ListOutputsArgs): ValidListOutputs
915
918
  includeTags: defaultFalse(args.includeTags),
916
919
  includeLabels: defaultFalse(args.includeLabels),
917
920
  limit: validateInteger(args.limit, 'limit', 10, 1, 10000),
918
- offset: validateInteger(args.offset, 'offset', 0, 0),
921
+ offset: validateInteger(args.offset, 'offset', 0, undefined, undefined),
919
922
  seekPermission: defaultTrue(args.seekPermission),
920
923
  knownTxids: []
921
924
  }
@@ -3,7 +3,7 @@ import { TableOutput, TableOutputBasket, TableOutputTag } from '../index.client'
3
3
  import { asString, sdk, verifyId, verifyOne } from '../../index.client'
4
4
  import { getBasketToSpecOp, ListOutputsSpecOp } from './ListOutputsSpecOp'
5
5
  import { StorageIdb } from '../StorageIdb'
6
- import { TransactionStatus } from '../../sdk'
6
+ import { TransactionStatus, WERR_NOT_IMPLEMENTED } from '../../sdk'
7
7
 
8
8
  export async function listOutputsIdb(
9
9
  storage: StorageIdb,
@@ -14,6 +14,7 @@ export async function listOutputsIdb(
14
14
  const userId = verifyId(auth.userId)
15
15
  const limit = vargs.limit
16
16
  const offset = vargs.offset
17
+ if (offset < 0) throw new WERR_NOT_IMPLEMENTED('Negative offset not supported in IndexedDB')
17
18
 
18
19
  const r: ListOutputsResult = {
19
20
  totalOutputs: 0,
@@ -13,7 +13,12 @@ export async function listOutputs(
13
13
  const trx: sdk.TrxToken | undefined = undefined
14
14
  const userId = verifyId(auth.userId)
15
15
  const limit = vargs.limit
16
- const offset = vargs.offset
16
+ let offset = vargs.offset
17
+ let orderBy: 'asc' | 'desc' = 'asc'
18
+ if (offset < 0) {
19
+ offset = -offset - 1
20
+ orderBy = 'desc'
21
+ }
17
22
 
18
23
  const k = dsk.toDb(trx)
19
24
 
@@ -23,14 +28,14 @@ export async function listOutputs(
23
28
  }
24
29
 
25
30
  /*
26
- ListOutputsArgs {
31
+ ValidListOutputsArgs {
27
32
  basket: BasketStringUnder300Bytes
28
33
 
29
- tags?: OutputTagStringUnder300Bytes[]
30
- tagQueryMode?: 'all' | 'any' // default any
34
+ tags: OutputTagStringUnder300Bytes[]
35
+ tagQueryMode: 'all' | 'any' // default any
31
36
 
32
- limit?: PositiveIntegerDefault10Max10000
33
- offset?: PositiveIntegerOrZero
37
+ limit: PositiveIntegerDefault10Max10000 // default 10
38
+ offset: number // default 0
34
39
  }
35
40
  */
36
41
 
@@ -166,7 +171,7 @@ export async function listOutputs(
166
171
  // Sort order when limit and offset are possible must be ascending for determinism.
167
172
  if (!specOp || !specOp.ignoreLimit) q.limit(limit).offset(offset)
168
173
 
169
- q.orderBy('outputId', 'asc')
174
+ q.orderBy('outputId', orderBy)
170
175
 
171
176
  let outputs: TableOutput[] = await q
172
177
 
@@ -3,7 +3,8 @@ import {
3
3
  Beef,
4
4
  ListOutputsArgs,
5
5
  OriginatorDomainNameStringUnder250Bytes,
6
- OutputTagStringUnder300Bytes
6
+ OutputTagStringUnder300Bytes,
7
+ WalletOutput
7
8
  } from '@bsv/sdk'
8
9
  import { _tu, TestWalletProviderNoSetup } from '../../utils/TestUtilsWalletStorage'
9
10
  import path from 'path'
@@ -340,4 +341,75 @@ describe('listOutputs test', () => {
340
341
  })
341
342
  }
342
343
  })
344
+
345
+ test('13 offsets', async () => {
346
+ let i = -1
347
+ for (const { wallet } of ctxs) {
348
+ i++
349
+ let totalOutputs: number = 0
350
+ const limit = 4
351
+ let allOutputs: WalletOutput[] = []
352
+ {
353
+ const args: ListOutputsArgs = {
354
+ basket: 'default'
355
+ }
356
+ const r = await wallet.listOutputs(args)
357
+ totalOutputs = r.totalOutputs
358
+ }
359
+ {
360
+ const args: ListOutputsArgs = {
361
+ basket: 'default',
362
+ offset: 0,
363
+ limit: totalOutputs
364
+ }
365
+ const r = await wallet.listOutputs(args)
366
+ expect(r.totalOutputs).toBe(totalOutputs)
367
+ expect(r.outputs.length).toBe(totalOutputs)
368
+ expect(r.totalOutputs).toBe(totalOutputs)
369
+ allOutputs = r.outputs
370
+ }
371
+ {
372
+ const args: ListOutputsArgs = {
373
+ basket: 'default',
374
+ offset: totalOutputs - limit,
375
+ limit
376
+ }
377
+ const r = await wallet.listOutputs(args)
378
+ expect(r.totalOutputs).toBe(totalOutputs)
379
+ expect(r.outputs.length).toBe(limit)
380
+ expect(r.outputs[0].outpoint).toBe(allOutputs[totalOutputs - limit].outpoint)
381
+ expect(r.outputs[1].outpoint).toBe(allOutputs[totalOutputs - limit + 1].outpoint)
382
+ expect(r.outputs[2].outpoint).toBe(allOutputs[totalOutputs - limit + 2].outpoint)
383
+ expect(r.outputs[3].outpoint).toBe(allOutputs[totalOutputs - limit + 3].outpoint)
384
+ }
385
+ if (i === 1) {
386
+ const args: ListOutputsArgs = {
387
+ basket: 'default',
388
+ offset: -1,
389
+ limit
390
+ }
391
+ const r = await wallet.listOutputs(args)
392
+ expect(r.totalOutputs).toBe(totalOutputs)
393
+ expect(r.outputs.length).toBe(limit)
394
+ expect(r.outputs[0].outpoint).toBe(allOutputs[totalOutputs - 1].outpoint)
395
+ expect(r.outputs[1].outpoint).toBe(allOutputs[totalOutputs - 2].outpoint)
396
+ expect(r.outputs[2].outpoint).toBe(allOutputs[totalOutputs - 3].outpoint)
397
+ expect(r.outputs[3].outpoint).toBe(allOutputs[totalOutputs - 4].outpoint)
398
+ }
399
+ if (i === 1) {
400
+ const args: ListOutputsArgs = {
401
+ basket: 'default',
402
+ offset: -3,
403
+ limit
404
+ }
405
+ const r = await wallet.listOutputs(args)
406
+ expect(r.totalOutputs).toBe(totalOutputs)
407
+ expect(r.outputs.length).toBe(limit)
408
+ expect(r.outputs[0].outpoint).toBe(allOutputs[totalOutputs - 3].outpoint)
409
+ expect(r.outputs[1].outpoint).toBe(allOutputs[totalOutputs - 4].outpoint)
410
+ expect(r.outputs[2].outpoint).toBe(allOutputs[totalOutputs - 5].outpoint)
411
+ expect(r.outputs[3].outpoint).toBe(allOutputs[totalOutputs - 6].outpoint)
412
+ }
413
+ }
414
+ })
343
415
  })