@bsv/wallet-toolbox 1.3.25 → 1.3.26

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 (45) hide show
  1. package/mobile/out/src/sdk/WalletServices.interfaces.d.ts +100 -0
  2. package/mobile/out/src/sdk/WalletServices.interfaces.d.ts.map +1 -1
  3. package/mobile/out/src/services/ServiceCollection.d.ts +28 -18
  4. package/mobile/out/src/services/ServiceCollection.d.ts.map +1 -1
  5. package/mobile/out/src/services/ServiceCollection.js +90 -38
  6. package/mobile/out/src/services/ServiceCollection.js.map +1 -1
  7. package/mobile/out/src/services/Services.d.ts +2 -9
  8. package/mobile/out/src/services/Services.d.ts.map +1 -1
  9. package/mobile/out/src/services/Services.js +12 -9
  10. package/mobile/out/src/services/Services.js.map +1 -1
  11. package/mobile/out/src/storage/StorageProvider.d.ts +6 -1
  12. package/mobile/out/src/storage/StorageProvider.d.ts.map +1 -1
  13. package/mobile/out/src/storage/StorageProvider.js.map +1 -1
  14. package/mobile/package-lock.json +6 -6
  15. package/mobile/package.json +2 -2
  16. package/out/src/sdk/WalletServices.interfaces.d.ts +100 -0
  17. package/out/src/sdk/WalletServices.interfaces.d.ts.map +1 -1
  18. package/out/src/services/ServiceCollection.d.ts +28 -18
  19. package/out/src/services/ServiceCollection.d.ts.map +1 -1
  20. package/out/src/services/ServiceCollection.js +90 -38
  21. package/out/src/services/ServiceCollection.js.map +1 -1
  22. package/out/src/services/Services.d.ts +2 -9
  23. package/out/src/services/Services.d.ts.map +1 -1
  24. package/out/src/services/Services.js +12 -9
  25. package/out/src/services/Services.js.map +1 -1
  26. package/out/src/storage/StorageKnex.d.ts +2 -2
  27. package/out/src/storage/StorageKnex.d.ts.map +1 -1
  28. package/out/src/storage/StorageKnex.js +5 -0
  29. package/out/src/storage/StorageKnex.js.map +1 -1
  30. package/out/src/storage/StorageProvider.d.ts +6 -1
  31. package/out/src/storage/StorageProvider.d.ts.map +1 -1
  32. package/out/src/storage/StorageProvider.js.map +1 -1
  33. package/out/src/storage/schema/entities/__tests/ProvenTxTests.test.js +11 -1
  34. package/out/src/storage/schema/entities/__tests/ProvenTxTests.test.js.map +1 -1
  35. package/out/test/Wallet/local/localWallet.man.test.js +3 -1
  36. package/out/test/Wallet/local/localWallet.man.test.js.map +1 -1
  37. package/out/tsconfig.all.tsbuildinfo +1 -1
  38. package/package.json +2 -2
  39. package/src/sdk/WalletServices.interfaces.ts +103 -0
  40. package/src/services/ServiceCollection.ts +114 -54
  41. package/src/services/Services.ts +15 -11
  42. package/src/storage/StorageKnex.ts +10 -3
  43. package/src/storage/StorageProvider.ts +7 -1
  44. package/src/storage/schema/entities/__tests/ProvenTxTests.test.ts +12 -1
  45. package/test/Wallet/local/localWallet.man.test.ts +3 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bsv/wallet-toolbox",
3
- "version": "1.3.25",
3
+ "version": "1.3.26",
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",
@@ -32,7 +32,7 @@
32
32
  "dependencies": {
33
33
  "@bsv/auth-express-middleware": "^1.1.2",
34
34
  "@bsv/payment-express-middleware": "^1.0.6",
35
- "@bsv/sdk": "^1.5.1",
35
+ "@bsv/sdk": "^1.5.2",
36
36
  "express": "^4.21.2",
37
37
  "idb": "^8.0.2",
38
38
  "knex": "^3.1.0",
@@ -168,6 +168,12 @@ export interface WalletServices {
168
168
  * @param txid
169
169
  */
170
170
  getBeefForTxid(txid: string): Promise<Beef>
171
+
172
+ /**
173
+ * @param reset if true, ends current interval and starts a new one.
174
+ * @returns a history of service calls made to the configured services.
175
+ */
176
+ getServicesCallHistory(reset?: boolean) : ServicesCallHistory
171
177
  }
172
178
 
173
179
  export type ScriptHashFormat = 'hashLE' | 'hashBE' | 'script'
@@ -497,3 +503,100 @@ export type UpdateFiatExchangeRateService = (
497
503
  targetCurrencies: string[],
498
504
  options: WalletServicesOptions
499
505
  ) => Promise<FiatExchangeRates>
506
+
507
+ /**
508
+ * Type for the service call history returned by Services.getServicesCallHistory.
509
+ */
510
+ export type ServicesCallHistory = {
511
+ version: number
512
+ getMerklePath: ServiceCallHistory
513
+ getRawTx: ServiceCallHistory
514
+ postBeef: ServiceCallHistory
515
+ getUtxoStatus: ServiceCallHistory
516
+ getStatusForTxids: ServiceCallHistory
517
+ getScriptHashHistory: ServiceCallHistory
518
+ updateFiatExchangeRates: ServiceCallHistory
519
+ }
520
+
521
+ /**
522
+ * Minimum data tracked for each service call.
523
+ */
524
+ export interface ServiceCall {
525
+ /**
526
+ * string value must be Date's toISOString format.
527
+ */
528
+ when: Date | string
529
+ msecs: number
530
+ /**
531
+ * true iff service provider successfully processed the request
532
+ * false iff service provider failed to process the request which includes thrown errors.
533
+ */
534
+ success: boolean
535
+ /**
536
+ * Simple text summary of result. e.g. `not a valid utxo` or `valid utxo`
537
+ */
538
+ result?: string
539
+ /**
540
+ * Error code and message iff success is false and a exception was thrown.
541
+ */
542
+ error?: { message: string, code: string }
543
+ }
544
+
545
+ /**
546
+ * Counts of service calls over a time interval.
547
+ */
548
+ export interface ServiceCallHistoryCounts {
549
+ /**
550
+ * count of calls returning success true.
551
+ */
552
+ success: number
553
+ /**
554
+ * count of calls returning success false.
555
+ */
556
+ failure: number
557
+ /**
558
+ * of failures (success false), count of calls with valid error code and message.
559
+ */
560
+ error: number
561
+ /**
562
+ * Counts are of calls over interval `since` to `until`.
563
+ * string value must be Date's toISOString format.
564
+ */
565
+ since: Date | string
566
+ /**
567
+ * Counts are of calls over interval `since` to `until`.
568
+ * string value must be Date's toISOString format.
569
+ */
570
+ until: Date | string
571
+ }
572
+
573
+ /**
574
+ * History of service calls for a single service, single provider.
575
+ */
576
+ export interface ProviderCallHistory {
577
+ providerName: string
578
+ serviceName: string
579
+ /**
580
+ * Most recent service calls.
581
+ * Array length is limited by Services configuration.
582
+ */
583
+ calls: ServiceCall[]
584
+ /**
585
+ * Counts since creation of Services instance.
586
+ */
587
+ totalCounts: ServiceCallHistoryCounts
588
+ /**
589
+ * Entry [0] is always the current interval being extended by new calls.
590
+ * when `getServiceCallHistory` with `reset` true is called, a new interval with zero counts is added to the start of array.
591
+ * Array length is limited by Services configuration.
592
+ */
593
+ resetCounts: ServiceCallHistoryCounts[]
594
+ }
595
+
596
+ /**
597
+ * History of service calls for a single service, all providers.
598
+ */
599
+ export interface ServiceCallHistory {
600
+ serviceName: string
601
+ historyByProvider: Record<string, ProviderCallHistory>
602
+ }
@@ -1,13 +1,20 @@
1
1
  import { WalletError } from "../sdk/WalletError";
2
+ import { ProviderCallHistory, ServiceCallHistory } from "../sdk/WalletServices.interfaces";
3
+
4
+ const MAX_RESET_COUNTS = 32
5
+ const MAX_CALL_HISTORY = 32
2
6
 
3
7
  export class ServiceCollection<T> {
4
- since: Date
5
8
  services: { name: string; service: T }[]
6
9
  _index: number
7
10
 
8
- _callHistory: Record<string, ServiceCallHistory> = {}
11
+ /**
12
+ * Start of currentCounts interval. Initially instance construction time.
13
+ */
14
+ readonly since: Date
15
+ _historyByProvider: Record<string, ProviderCallHistory> = {}
9
16
 
10
- constructor(services?: { name: string; service: T }[]) {
17
+ constructor(public serviceName: string, services?: { name: string; service: T }[]) {
11
18
  this.services = services || []
12
19
  this._index = 0
13
20
  this.since = new Date()
@@ -34,8 +41,8 @@ export class ServiceCollection<T> {
34
41
  const i = this._index
35
42
  const name = this.services[i].name
36
43
  const service = this.services[i].service
37
- const call = { name, when: new Date(), durationMsecs: 0, success: false, result: undefined, error: undefined }
38
- return { name, service, call }
44
+ const call = { name, when: new Date(), msecs: 0, success: false, result: undefined, error: undefined }
45
+ return { serviceName: this.serviceName, providerName: name, service, call }
39
46
  }
40
47
 
41
48
  get allServicesToCall(): ServiceToCall<T>[] {
@@ -68,28 +75,44 @@ export class ServiceCollection<T> {
68
75
  }
69
76
 
70
77
  clone(): ServiceCollection<T> {
71
- return new ServiceCollection([...this.services])
78
+ return new ServiceCollection(this.serviceName, [...this.services])
72
79
  }
73
80
 
74
- _addServiceCall(name: string, call: ServiceCall): ServiceCallHistory {
75
- let h = this._callHistory[name]
81
+ _addServiceCall(providerName: string, call: ServiceCall): ProviderCallHistory {
82
+ const now = new Date()
83
+ let h = this._historyByProvider[providerName]
76
84
  if (!h) {
77
- h = { name, calls: [], count: 0, countError: 0, countFailure: 0, countSuccess: 0, since: this.since }
78
- this._callHistory[name] = h
85
+ h = {
86
+ serviceName: this.serviceName,
87
+ providerName: providerName,
88
+ calls: [],
89
+ totalCounts: { success: 0, failure: 0, error: 0, since: this.since, until: now },
90
+ resetCounts: [{ success: 0, failure: 0, error: 0, since: this.since, until: now }]
91
+ }
92
+ this._historyByProvider[providerName] = h
79
93
  }
80
- h.calls.push(call)
81
- h.count++
82
- h.calls = h.calls.slice(-32)
94
+ h.calls.unshift(call)
95
+ h.calls = h.calls.slice(0,MAX_CALL_HISTORY)
96
+ h.totalCounts.until = now
97
+ h.resetCounts[0].until = now
83
98
  return h
84
99
  }
85
100
 
101
+ getDuration(since: Date | string): number {
102
+ const now = new Date()
103
+ if (typeof since === 'string') since = new Date(since)
104
+ return now.getTime() - since.getTime()
105
+ }
106
+
86
107
  addServiceCallSuccess(stc: ServiceToCall<T>, result?: string): void {
87
108
  const call = stc.call
88
109
  call.success = true
89
110
  call.result = result
90
111
  call.error = undefined
91
- call.durationMsecs = new Date().getTime() - call.when.getTime()
92
- this._addServiceCall(this.name, call).countSuccess++
112
+ call.msecs = this.getDuration(call.when)
113
+ const h = this._addServiceCall(stc.providerName, call)
114
+ h.totalCounts.success++
115
+ h.resetCounts[0].success++
93
116
  }
94
117
 
95
118
  addServiceCallFailure(stc: ServiceToCall<T>, result?: string): void {
@@ -97,8 +120,10 @@ export class ServiceCollection<T> {
97
120
  call.success = false
98
121
  call.result = result
99
122
  call.error = undefined
100
- call.durationMsecs = new Date().getTime() - call.when.getTime()
101
- this._addServiceCall(this.name, call).countFailure++
123
+ call.msecs = this.getDuration(call.when)
124
+ const h = this._addServiceCall(this.name, call)
125
+ h.totalCounts.failure++
126
+ h.resetCounts[0].failure++
102
127
  }
103
128
 
104
129
  addServiceCallError(stc: ServiceToCall<T>, error: WalletError): void {
@@ -106,66 +131,101 @@ export class ServiceCollection<T> {
106
131
  call.success = false
107
132
  call.result = undefined
108
133
  call.error = error
109
- call.durationMsecs = new Date().getTime() - call.when.getTime()
110
- this._addServiceCall(this.name, call).countError++
134
+ call.msecs = this.getDuration(call.when)
135
+ const h = this._addServiceCall(this.name, call)
136
+ h.totalCounts.failure++
137
+ h.totalCounts.error++
138
+ h.resetCounts[0].failure++
139
+ h.resetCounts[0].error++
111
140
  }
112
141
 
113
142
  /**
114
143
  * @returns A copy of current service call history
115
144
  */
116
- getServiceCallHistory(reset?: boolean): Record<string, ServiceCallHistory> {
117
- const histories: Record<string, ServiceCallHistory> = {}
118
- for (const name of Object.keys(this._callHistory)) {
119
- const h = this._callHistory[name]
120
- histories[name] = {
121
- name: h.name,
122
- count: h.count,
123
- countError: h.countError,
124
- countFailure: h.countFailure,
125
- countSuccess: h.countSuccess,
126
- since: h.since,
145
+ getServiceCallHistory(reset?: boolean): ServiceCallHistory {
146
+ const now = new Date()
147
+ const history: ServiceCallHistory = { serviceName: this.serviceName, historyByProvider: {} }
148
+ for (const name of Object.keys(this._historyByProvider)) {
149
+ const h = this._historyByProvider[name]
150
+ const c: ProviderCallHistory = {
151
+ serviceName: h.serviceName,
152
+ providerName: h.providerName,
127
153
  calls: h.calls.map(c => ({
128
- name: c.name,
129
- when: c.when,
130
- durationMsecs: c.durationMsecs,
154
+ when: dateToString(c.when),
155
+ msecs: c.msecs,
131
156
  success: c.success,
132
157
  result: c.result,
133
158
  error: c.error ? { message: c.error.message, code: c.error.code } : undefined
134
- }))
159
+ })),
160
+ totalCounts: {
161
+ success: h.totalCounts.success,
162
+ failure: h.totalCounts.failure,
163
+ error: h.totalCounts.error,
164
+ since: dateToString(h.totalCounts.since),
165
+ until: dateToString(h.totalCounts.until)
166
+ },
167
+ resetCounts: []
168
+ }
169
+ for (let i = 0; i < h.resetCounts.length; i++) {
170
+ const r = h.resetCounts[i]
171
+ c.resetCounts.push({
172
+ success: r.success,
173
+ failure: r.failure,
174
+ error: r.error,
175
+ since: dateToString(r.since),
176
+ until: dateToString(r.until)
177
+ })
135
178
  }
179
+ history.historyByProvider[name] = c
136
180
  if (reset) {
137
- h.count = 0
138
- h.countError = 0
139
- h.countFailure = 0
140
- h.countSuccess = 0
141
- h.since = new Date()
181
+ // Make sure intervals are continuous.
182
+ h.resetCounts[0].until = now
183
+ // insert a new resetCounts interval
184
+ h.resetCounts.unshift({
185
+ success: 0,
186
+ failure: 0,
187
+ error: 0,
188
+ // start of new interval
189
+ since: now,
190
+ // end of new interval, gets bumped with each new call added
191
+ until: now
192
+ })
193
+ // limit history to most recent intervals
194
+ h.resetCounts = h.resetCounts.slice(0, MAX_CALL_HISTORY)
142
195
  }
143
196
  }
144
- return histories
197
+ return history
198
+
199
+ function dateToString(d: Date | string): string {
200
+ return typeof d === 'string' ? d : d.toISOString()
201
+ }
145
202
  }
146
203
  }
147
204
 
148
205
  export interface ServiceCall {
149
- name: string
150
- when: Date
151
- durationMsecs: number
206
+ /**
207
+ * string value must be Date's toISOString format.
208
+ */
209
+ when: Date | string
210
+ msecs: number
211
+ /**
212
+ * true iff service provider successfully processed the request
213
+ * false iff service provider failed to process the request which includes thrown errors.
214
+ */
152
215
  success: boolean
216
+ /**
217
+ * Simple text summary of result. e.g. `not a valid utxo` or `valid utxo`
218
+ */
153
219
  result?: string
220
+ /**
221
+ * Error code and message iff success is false and a exception was thrown.
222
+ */
154
223
  error?: { message: string, code: string }
155
224
  }
156
225
 
157
- export interface ServiceCallHistory {
158
- name: string
159
- calls: ServiceCall[]
160
- count: number
161
- countSuccess: number
162
- countFailure: number
163
- countError: number
164
- since: Date
165
- }
166
-
167
226
  export interface ServiceToCall<T> {
168
- name: string
227
+ providerName: string
228
+ serviceName: string
169
229
  service: T
170
230
  call: ServiceCall
171
231
  }
@@ -1,6 +1,6 @@
1
1
  import { Transaction as BsvTransaction, Beef, ChainTracker, Utils } from '@bsv/sdk'
2
2
  import { asArray, asString, doubleSha256BE, sdk, sha256Hash, TableOutput, wait } from '../index.client'
3
- import { ServiceCall, ServiceCollection } from './ServiceCollection'
3
+ import { ServiceCollection } from './ServiceCollection'
4
4
  import { createDefaultWalletServicesOptions } from './createDefaultWalletServicesOptions'
5
5
  import { ChaintracksChainTracker } from './chaintracker'
6
6
  import { WhatsOnChain } from './providers/WhatsOnChain'
@@ -8,6 +8,7 @@ import { updateChaintracksFiatExchangeRates, updateExchangeratesapi } from './pr
8
8
  import { ARC } from './providers/ARC'
9
9
  import { Bitails } from './providers/Bitails'
10
10
  import { getBeefForTxid } from './providers/getBeefForTxid'
11
+ import { ServicesCallHistory } from '../sdk/WalletServices.interfaces'
11
12
 
12
13
  export class Services implements sdk.WalletServices {
13
14
  static createDefaultOptions(chain: sdk.Chain): sdk.WalletServicesOptions {
@@ -45,15 +46,15 @@ export class Services implements sdk.WalletServices {
45
46
  this.bitails = new Bitails(this.chain)
46
47
 
47
48
  //prettier-ignore
48
- this.getMerklePathServices = new ServiceCollection<sdk.GetMerklePathService>()
49
+ this.getMerklePathServices = new ServiceCollection<sdk.GetMerklePathService>('getMerklePath')
49
50
  .add({ name: 'WhatsOnChain', service: this.whatsonchain.getMerklePath.bind(this.whatsonchain) })
50
51
  .add({ name: 'Bitails', service: this.bitails.getMerklePath.bind(this.bitails) })
51
52
 
52
53
  //prettier-ignore
53
- this.getRawTxServices = new ServiceCollection<sdk.GetRawTxService>()
54
+ this.getRawTxServices = new ServiceCollection<sdk.GetRawTxService>('getRawTx')
54
55
  .add({ name: 'WhatsOnChain', service: this.whatsonchain.getRawTxResult.bind(this.whatsonchain) })
55
56
 
56
- this.postBeefServices = new ServiceCollection<sdk.PostBeefService>()
57
+ this.postBeefServices = new ServiceCollection<sdk.PostBeefService>('postBeef')
57
58
  if (this.arcGorillaPool) {
58
59
  //prettier-ignore
59
60
  this.postBeefServices.add({ name: 'GorillaPool', service: this.arcGorillaPool.postBeef.bind(this.arcGorillaPool) })
@@ -66,32 +67,33 @@ export class Services implements sdk.WalletServices {
66
67
  ;
67
68
 
68
69
  //prettier-ignore
69
- this.getUtxoStatusServices = new ServiceCollection<sdk.GetUtxoStatusService>()
70
+ this.getUtxoStatusServices = new ServiceCollection<sdk.GetUtxoStatusService>('getUtxoStatus')
70
71
  .add({ name: 'WhatsOnChain', service: this.whatsonchain.getUtxoStatus.bind(this.whatsonchain) })
71
72
 
72
73
  //prettier-ignore
73
- this.getStatusForTxidsServices = new ServiceCollection<sdk.GetStatusForTxidsService>()
74
+ this.getStatusForTxidsServices = new ServiceCollection<sdk.GetStatusForTxidsService>('getStatusForTxids')
74
75
  .add({ name: 'WhatsOnChain', service: this.whatsonchain.getStatusForTxids.bind(this.whatsonchain) })
75
76
 
76
77
  //prettier-ignore
77
- this.getScriptHashHistoryServices = new ServiceCollection<sdk.GetScriptHashHistoryService>()
78
+ this.getScriptHashHistoryServices = new ServiceCollection<sdk.GetScriptHashHistoryService>('getScriptHashHistory')
78
79
  .add({ name: 'WhatsOnChain', service: this.whatsonchain.getScriptHashHistory.bind(this.whatsonchain) })
79
80
 
80
81
  //prettier-ignore
81
- this.updateFiatExchangeRateServices = new ServiceCollection<sdk.UpdateFiatExchangeRateService>()
82
+ this.updateFiatExchangeRateServices = new ServiceCollection<sdk.UpdateFiatExchangeRateService>('updateFiatExchangeRate')
82
83
  .add({ name: 'ChaintracksService', service: updateChaintracksFiatExchangeRates })
83
84
  .add({ name: 'exchangeratesapi', service: updateExchangeratesapi })
84
85
  }
85
86
 
86
- getServicesCallHistory(reset?: boolean) {
87
+ getServicesCallHistory(reset?: boolean) : ServicesCallHistory {
87
88
  return {
88
- version: 1,
89
+ version: 2,
89
90
  getMerklePath: this.getMerklePathServices.getServiceCallHistory(reset),
90
91
  getRawTx: this.getRawTxServices.getServiceCallHistory(reset),
91
92
  postBeef: this.postBeefServices.getServiceCallHistory(reset),
92
93
  getUtxoStatus: this.getUtxoStatusServices.getServiceCallHistory(reset),
93
94
  getStatusForTxids: this.getStatusForTxidsServices.getServiceCallHistory(reset),
94
- getScriptHashHistory: this.getScriptHashHistoryServices.getServiceCallHistory(reset)
95
+ getScriptHashHistory: this.getScriptHashHistoryServices.getServiceCallHistory(reset),
96
+ updateFiatExchangeRates: this.updateFiatExchangeRateServices.getServiceCallHistory(reset)
95
97
  }
96
98
  }
97
99
 
@@ -319,6 +321,8 @@ export class Services implements sdk.WalletServices {
319
321
 
320
322
  if (r.error)
321
323
  services.addServiceCallError(stc, r.error)
324
+ else if (!r.rawTx)
325
+ services.addServiceCallSuccess(stc, `not found`)
322
326
  else
323
327
  services.addServiceCallFailure(stc)
324
328
 
@@ -23,12 +23,13 @@ import {
23
23
  } from './schema/tables'
24
24
  import { KnexMigrations } from './schema/KnexMigrations'
25
25
  import { Knex } from 'knex'
26
- import { StorageAdminStats, StorageProvider, StorageProviderOptions } from './StorageProvider'
26
+ import { AdminStatsResult, StorageProvider, StorageProviderOptions } from './StorageProvider'
27
27
  import { purgeData } from './methods/purgeData'
28
28
  import { listActions } from './methods/listActionsKnex'
29
29
  import { listOutputs } from './methods/listOutputsKnex'
30
30
  import { DBType } from './StorageReader'
31
31
  import { reviewStatus } from './methods/reviewStatus'
32
+ import { ServicesCallHistory } from '../sdk/WalletServices.interfaces'
32
33
 
33
34
  export interface StorageKnexOptions extends StorageProviderOptions {
34
35
  /**
@@ -1152,9 +1153,13 @@ export class StorageKnex extends StorageProvider implements sdk.WalletStoragePro
1152
1153
  return entities
1153
1154
  }
1154
1155
 
1155
- async adminStats(adminIdentityKey: string): Promise<StorageAdminStats> {
1156
+ async adminStats(adminIdentityKey: string): Promise<AdminStatsResult> {
1156
1157
  if (this.dbtype !== 'MySQL') throw new sdk.WERR_NOT_IMPLEMENTED('adminStats, only MySQL is supported')
1157
1158
 
1159
+ const monitorEvent = verifyOneOrNone(await this.findMonitorEvents({ partial: { event: 'ServiceCallHistory'}, orderDescending: true, paged: { limit: 1 } }))
1160
+ const monitorStats: ServicesCallHistory | undefined = monitorEvent ? JSON.parse(monitorEvent.details!) : undefined
1161
+ const servicesStats = this.getServices().getServicesCallHistory(true)
1162
+
1158
1163
  const one_day_ago = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString()
1159
1164
  const one_week_ago = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString()
1160
1165
  const one_month_ago = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString()
@@ -1295,7 +1300,9 @@ select
1295
1300
  (select count(*) from output_tags where created_at > '${one_month_ago}') as tagsMonth,
1296
1301
  (select count(*) from output_tags) as tagsTotal
1297
1302
  `)
1298
- const r: StorageAdminStats = {
1303
+ const r: AdminStatsResult = {
1304
+ monitorStats,
1305
+ servicesStats,
1299
1306
  requestedBy: adminIdentityKey,
1300
1307
  when: new Date().toISOString(),
1301
1308
  usersDay,
@@ -40,6 +40,7 @@ import { createAction } from './methods/createAction'
40
40
  import { internalizeAction } from './methods/internalizeAction'
41
41
  import { StorageReaderWriter, StorageReaderWriterOptions } from './StorageReaderWriter'
42
42
  import { EntityProvenTx, EntityProvenTxReq, EntitySyncState, EntityTransaction } from './schema/entities'
43
+ import { ServicesCallHistory } from '../sdk/WalletServices.interfaces'
43
44
 
44
45
  export abstract class StorageProvider extends StorageReaderWriter implements sdk.WalletStorageProvider {
45
46
  isDirty = false
@@ -106,7 +107,7 @@ export abstract class StorageProvider extends StorageReaderWriter implements sdk
106
107
  abstract findOutputsAuth(auth: sdk.AuthId, args: sdk.FindOutputsArgs): Promise<TableOutput[]>
107
108
  abstract insertCertificateAuth(auth: sdk.AuthId, certificate: TableCertificateX): Promise<number>
108
109
 
109
- abstract adminStats(adminIdentityKey: string): Promise<StorageAdminStats>
110
+ abstract adminStats(adminIdentityKey: string): Promise<AdminStatsResult>
110
111
 
111
112
  override isStorageProvider(): boolean {
112
113
  return true
@@ -773,3 +774,8 @@ export interface StorageAdminStats {
773
774
  tagsMonth: number
774
775
  tagsTotal: number
775
776
  }
777
+
778
+ export interface AdminStatsResult extends StorageAdminStats {
779
+ servicesStats?: ServicesCallHistory
780
+ monitorStats?: ServicesCallHistory
781
+ }
@@ -136,7 +136,18 @@ describe('ProvenTx class method tests', () => {
136
136
  }),
137
137
  nLockTimeIsFinal: async () => true,
138
138
 
139
- getBeefForTxid: async () => new bsv.Beef()
139
+ getBeefForTxid: async () => new bsv.Beef(),
140
+
141
+ getServicesCallHistory: () => ({
142
+ version: 1,
143
+ getMerklePath: { serviceName: '', historyByProvider: {} },
144
+ getRawTx: { serviceName: '', historyByProvider: {} },
145
+ postBeef: { serviceName: '', historyByProvider: {} },
146
+ getStatusForTxids: { serviceName: '', historyByProvider: {} },
147
+ getUtxoStatus: { serviceName: '', historyByProvider: {} },
148
+ getScriptHashHistory: { serviceName: '', historyByProvider: {} },
149
+ updateFiatExchangeRates: { serviceName: '', historyByProvider: {} }
150
+ })
140
151
  }
141
152
 
142
153
  // Call the method under test
@@ -1,5 +1,5 @@
1
1
  import { EntitySyncState, sdk } from '../../../src'
2
- import { _tu } from '../../utils/TestUtilsWalletStorage'
2
+ import { _tu, logger } from '../../utils/TestUtilsWalletStorage'
3
3
  import { specOpInvalidChange } from '../../../src/sdk'
4
4
  import { createOneSatTestOutput, createSetup, LocalWalletTestOptions } from '../../utils/localWalletMethods'
5
5
 
@@ -32,9 +32,10 @@ describe('localWallet tests', () => {
32
32
  expect(key.publicKey.toString()).toBe(setup.identityKey)
33
33
  await setup.services.getRawTx('6dd8e416dfaf14c04899ccad2bf76a67c1d5598fece25cf4dcb7a076012b7d8d')
34
34
  await setup.services.getRawTx('ac9cced61e2491be55061ce6577e0c59b909922ba92d5cc1cd754b10d721ab0e')
35
+ await setup.monitor.runOnce()
35
36
  await setup.services.getRawTx('0000e416dfaf14c04899ccad2bf76a67c1d5598fece25cf4dcb7a076012b7d8d')
36
37
  await setup.services.getRawTx('0000ced61e2491be55061ce6577e0c59b909922ba92d5cc1cd754b10d721ab0e')
37
- await setup.monitor.runOnce()
38
+ logger(await setup.monitor.runTask('ServiceCallHistory'))
38
39
  await setup.wallet.destroy()
39
40
  })
40
41