@bsv/wallet-toolbox 1.3.24 → 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.
- package/mobile/out/src/monitor/Monitor.d.ts.map +1 -1
- package/mobile/out/src/monitor/Monitor.js +4 -0
- package/mobile/out/src/monitor/Monitor.js.map +1 -1
- package/mobile/out/src/monitor/tasks/TaskServiceCallHistory.d.ts +12 -0
- package/mobile/out/src/monitor/tasks/TaskServiceCallHistory.d.ts.map +1 -0
- package/mobile/out/src/monitor/tasks/TaskServiceCallHistory.js +23 -0
- package/mobile/out/src/monitor/tasks/TaskServiceCallHistory.js.map +1 -0
- package/mobile/out/src/sdk/WalletServices.interfaces.d.ts +102 -0
- package/mobile/out/src/sdk/WalletServices.interfaces.d.ts.map +1 -1
- package/mobile/out/src/sdk/WalletStorage.interfaces.d.ts +5 -0
- package/mobile/out/src/sdk/WalletStorage.interfaces.d.ts.map +1 -1
- package/mobile/out/src/services/ServiceCollection.d.ts +49 -1
- package/mobile/out/src/services/ServiceCollection.d.ts.map +1 -1
- package/mobile/out/src/services/ServiceCollection.js +139 -2
- package/mobile/out/src/services/ServiceCollection.js.map +1 -1
- package/mobile/out/src/services/Services.d.ts +4 -2
- package/mobile/out/src/services/Services.d.ts.map +1 -1
- package/mobile/out/src/services/Services.js +168 -74
- package/mobile/out/src/services/Services.js.map +1 -1
- package/mobile/out/src/services/createDefaultWalletServicesOptions.d.ts +1 -0
- package/mobile/out/src/services/createDefaultWalletServicesOptions.d.ts.map +1 -1
- package/mobile/out/src/services/createDefaultWalletServicesOptions.js +15 -1
- package/mobile/out/src/services/createDefaultWalletServicesOptions.js.map +1 -1
- package/mobile/out/src/services/providers/ARC.d.ts +3 -2
- package/mobile/out/src/services/providers/ARC.d.ts.map +1 -1
- package/mobile/out/src/services/providers/ARC.js +5 -4
- package/mobile/out/src/services/providers/ARC.js.map +1 -1
- package/mobile/out/src/signer/methods/internalizeAction.d.ts.map +1 -1
- package/mobile/out/src/signer/methods/internalizeAction.js +3 -13
- package/mobile/out/src/signer/methods/internalizeAction.js.map +1 -1
- package/mobile/out/src/storage/StorageProvider.d.ts +6 -1
- package/mobile/out/src/storage/StorageProvider.d.ts.map +1 -1
- package/mobile/out/src/storage/StorageProvider.js +1 -1
- package/mobile/out/src/storage/StorageProvider.js.map +1 -1
- package/mobile/out/src/storage/methods/createAction.d.ts.map +1 -1
- package/mobile/out/src/storage/methods/createAction.js +5 -1
- package/mobile/out/src/storage/methods/createAction.js.map +1 -1
- package/mobile/out/src/storage/methods/internalizeAction.js +2 -1
- package/mobile/out/src/storage/methods/internalizeAction.js.map +1 -1
- package/mobile/package-lock.json +7 -6
- package/mobile/package.json +2 -2
- package/out/src/monitor/Monitor.d.ts.map +1 -1
- package/out/src/monitor/Monitor.js +4 -0
- package/out/src/monitor/Monitor.js.map +1 -1
- package/out/src/monitor/tasks/TaskServiceCallHistory.d.ts +12 -0
- package/out/src/monitor/tasks/TaskServiceCallHistory.d.ts.map +1 -0
- package/out/src/monitor/tasks/TaskServiceCallHistory.js +23 -0
- package/out/src/monitor/tasks/TaskServiceCallHistory.js.map +1 -0
- package/out/src/sdk/WalletServices.interfaces.d.ts +102 -0
- package/out/src/sdk/WalletServices.interfaces.d.ts.map +1 -1
- package/out/src/sdk/WalletStorage.interfaces.d.ts +5 -0
- package/out/src/sdk/WalletStorage.interfaces.d.ts.map +1 -1
- package/out/src/services/ServiceCollection.d.ts +49 -1
- package/out/src/services/ServiceCollection.d.ts.map +1 -1
- package/out/src/services/ServiceCollection.js +139 -2
- package/out/src/services/ServiceCollection.js.map +1 -1
- package/out/src/services/Services.d.ts +4 -2
- package/out/src/services/Services.d.ts.map +1 -1
- package/out/src/services/Services.js +168 -74
- package/out/src/services/Services.js.map +1 -1
- package/out/src/services/__tests/ArcGorillaPool.man.test.d.ts +2 -0
- package/out/src/services/__tests/ArcGorillaPool.man.test.d.ts.map +1 -0
- package/out/src/services/__tests/ArcGorillaPool.man.test.js +93 -0
- package/out/src/services/__tests/ArcGorillaPool.man.test.js.map +1 -0
- package/out/src/services/createDefaultWalletServicesOptions.d.ts +1 -0
- package/out/src/services/createDefaultWalletServicesOptions.d.ts.map +1 -1
- package/out/src/services/createDefaultWalletServicesOptions.js +15 -1
- package/out/src/services/createDefaultWalletServicesOptions.js.map +1 -1
- package/out/src/services/providers/ARC.d.ts +3 -2
- package/out/src/services/providers/ARC.d.ts.map +1 -1
- package/out/src/services/providers/ARC.js +5 -4
- package/out/src/services/providers/ARC.js.map +1 -1
- package/out/src/signer/methods/internalizeAction.d.ts.map +1 -1
- package/out/src/signer/methods/internalizeAction.js +3 -13
- package/out/src/signer/methods/internalizeAction.js.map +1 -1
- package/out/src/storage/StorageKnex.d.ts +2 -2
- package/out/src/storage/StorageKnex.d.ts.map +1 -1
- package/out/src/storage/StorageKnex.js +55 -2
- package/out/src/storage/StorageKnex.js.map +1 -1
- package/out/src/storage/StorageProvider.d.ts +6 -1
- package/out/src/storage/StorageProvider.d.ts.map +1 -1
- package/out/src/storage/StorageProvider.js +1 -1
- package/out/src/storage/StorageProvider.js.map +1 -1
- package/out/src/storage/methods/createAction.d.ts.map +1 -1
- package/out/src/storage/methods/createAction.js +5 -1
- package/out/src/storage/methods/createAction.js.map +1 -1
- package/out/src/storage/methods/internalizeAction.js +2 -1
- package/out/src/storage/methods/internalizeAction.js.map +1 -1
- package/out/src/storage/schema/KnexMigrations.d.ts.map +1 -1
- package/out/src/storage/schema/KnexMigrations.js +12 -0
- package/out/src/storage/schema/KnexMigrations.js.map +1 -1
- package/out/src/storage/schema/entities/__tests/ProvenTxTests.test.js +11 -1
- package/out/src/storage/schema/entities/__tests/ProvenTxTests.test.js.map +1 -1
- package/out/test/Wallet/local/localWallet.man.test.js +14 -16
- package/out/test/Wallet/local/localWallet.man.test.js.map +1 -1
- package/out/test/Wallet/support/operations.man.test.js +96 -6
- package/out/test/Wallet/support/operations.man.test.js.map +1 -1
- package/out/test/storage/KnexMigrations.test.js +1 -1
- package/out/test/storage/KnexMigrations.test.js.map +1 -1
- package/out/tsconfig.all.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/monitor/Monitor.ts +4 -0
- package/src/monitor/tasks/TaskServiceCallHistory.ts +26 -0
- package/src/sdk/WalletServices.interfaces.ts +105 -0
- package/src/sdk/WalletStorage.interfaces.ts +5 -0
- package/src/services/ServiceCollection.ts +183 -2
- package/src/services/Services.ts +166 -76
- package/src/services/__tests/ArcGorillaPool.man.test.ts +108 -0
- package/src/services/createDefaultWalletServicesOptions.ts +16 -1
- package/src/services/providers/ARC.ts +8 -6
- package/src/signer/methods/internalizeAction.ts +4 -14
- package/src/storage/StorageKnex.ts +35 -4
- package/src/storage/StorageProvider.ts +8 -2
- package/src/storage/methods/createAction.ts +5 -3
- package/src/storage/methods/internalizeAction.ts +2 -1
- package/src/storage/schema/KnexMigrations.ts +13 -0
- package/src/storage/schema/entities/__tests/ProvenTxTests.test.ts +12 -1
- package/test/Wallet/local/localWallet.man.test.ts +15 -17
- package/test/Wallet/support/operations.man.test.ts +107 -7
- package/test/storage/KnexMigrations.test.ts +1 -1
package/src/services/Services.ts
CHANGED
|
@@ -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 {
|
|
@@ -16,7 +17,8 @@ export class Services implements sdk.WalletServices {
|
|
|
16
17
|
|
|
17
18
|
options: sdk.WalletServicesOptions
|
|
18
19
|
whatsonchain: WhatsOnChain
|
|
19
|
-
|
|
20
|
+
arcTaal: ARC
|
|
21
|
+
arcGorillaPool?: ARC
|
|
20
22
|
bitails: Bitails
|
|
21
23
|
|
|
22
24
|
getMerklePathServices: ServiceCollection<sdk.GetMerklePathService>
|
|
@@ -36,43 +38,65 @@ export class Services implements sdk.WalletServices {
|
|
|
36
38
|
|
|
37
39
|
this.whatsonchain = new WhatsOnChain(this.chain, { apiKey: this.options.whatsOnChainApiKey }, this)
|
|
38
40
|
|
|
39
|
-
this.
|
|
41
|
+
this.arcTaal = new ARC(this.options.arcUrl, this.options.arcConfig, 'arcTaal')
|
|
42
|
+
if (this.options.arcGorillaPoolUrl) {
|
|
43
|
+
//this.arcGorillaPool = new ARC(this.options.arcGorillaPoolUrl, this.options.arcGorillaPoolConfig, 'arcGorillaPool')
|
|
44
|
+
}
|
|
40
45
|
|
|
41
46
|
this.bitails = new Bitails(this.chain)
|
|
42
47
|
|
|
43
48
|
//prettier-ignore
|
|
44
|
-
this.getMerklePathServices = new ServiceCollection<sdk.GetMerklePathService>()
|
|
49
|
+
this.getMerklePathServices = new ServiceCollection<sdk.GetMerklePathService>('getMerklePath')
|
|
45
50
|
.add({ name: 'WhatsOnChain', service: this.whatsonchain.getMerklePath.bind(this.whatsonchain) })
|
|
46
51
|
.add({ name: 'Bitails', service: this.bitails.getMerklePath.bind(this.bitails) })
|
|
47
52
|
|
|
48
53
|
//prettier-ignore
|
|
49
|
-
this.getRawTxServices = new ServiceCollection<sdk.GetRawTxService>()
|
|
54
|
+
this.getRawTxServices = new ServiceCollection<sdk.GetRawTxService>('getRawTx')
|
|
50
55
|
.add({ name: 'WhatsOnChain', service: this.whatsonchain.getRawTxResult.bind(this.whatsonchain) })
|
|
51
56
|
|
|
57
|
+
this.postBeefServices = new ServiceCollection<sdk.PostBeefService>('postBeef')
|
|
58
|
+
if (this.arcGorillaPool) {
|
|
59
|
+
//prettier-ignore
|
|
60
|
+
this.postBeefServices.add({ name: 'GorillaPool', service: this.arcGorillaPool.postBeef.bind(this.arcGorillaPool) })
|
|
61
|
+
}
|
|
52
62
|
//prettier-ignore
|
|
53
|
-
this.postBeefServices
|
|
54
|
-
.add({ name: 'TaalArcBeef', service: this.
|
|
63
|
+
this.postBeefServices
|
|
64
|
+
.add({ name: 'TaalArcBeef', service: this.arcTaal.postBeef.bind(this.arcTaal) })
|
|
55
65
|
.add({ name: 'WhatsOnChain', service: this.whatsonchain.postBeef.bind(this.whatsonchain) })
|
|
56
66
|
.add({ name: 'Bitails', service: this.bitails.postBeef.bind(this.bitails) })
|
|
67
|
+
;
|
|
57
68
|
|
|
58
69
|
//prettier-ignore
|
|
59
|
-
this.getUtxoStatusServices = new ServiceCollection<sdk.GetUtxoStatusService>()
|
|
70
|
+
this.getUtxoStatusServices = new ServiceCollection<sdk.GetUtxoStatusService>('getUtxoStatus')
|
|
60
71
|
.add({ name: 'WhatsOnChain', service: this.whatsonchain.getUtxoStatus.bind(this.whatsonchain) })
|
|
61
72
|
|
|
62
73
|
//prettier-ignore
|
|
63
|
-
this.getStatusForTxidsServices = new ServiceCollection<sdk.GetStatusForTxidsService>()
|
|
74
|
+
this.getStatusForTxidsServices = new ServiceCollection<sdk.GetStatusForTxidsService>('getStatusForTxids')
|
|
64
75
|
.add({ name: 'WhatsOnChain', service: this.whatsonchain.getStatusForTxids.bind(this.whatsonchain) })
|
|
65
76
|
|
|
66
77
|
//prettier-ignore
|
|
67
|
-
this.getScriptHashHistoryServices = new ServiceCollection<sdk.GetScriptHashHistoryService>()
|
|
78
|
+
this.getScriptHashHistoryServices = new ServiceCollection<sdk.GetScriptHashHistoryService>('getScriptHashHistory')
|
|
68
79
|
.add({ name: 'WhatsOnChain', service: this.whatsonchain.getScriptHashHistory.bind(this.whatsonchain) })
|
|
69
80
|
|
|
70
81
|
//prettier-ignore
|
|
71
|
-
this.updateFiatExchangeRateServices = new ServiceCollection<sdk.UpdateFiatExchangeRateService>()
|
|
82
|
+
this.updateFiatExchangeRateServices = new ServiceCollection<sdk.UpdateFiatExchangeRateService>('updateFiatExchangeRate')
|
|
72
83
|
.add({ name: 'ChaintracksService', service: updateChaintracksFiatExchangeRates })
|
|
73
84
|
.add({ name: 'exchangeratesapi', service: updateExchangeratesapi })
|
|
74
85
|
}
|
|
75
86
|
|
|
87
|
+
getServicesCallHistory(reset?: boolean) : ServicesCallHistory {
|
|
88
|
+
return {
|
|
89
|
+
version: 2,
|
|
90
|
+
getMerklePath: this.getMerklePathServices.getServiceCallHistory(reset),
|
|
91
|
+
getRawTx: this.getRawTxServices.getServiceCallHistory(reset),
|
|
92
|
+
postBeef: this.postBeefServices.getServiceCallHistory(reset),
|
|
93
|
+
getUtxoStatus: this.getUtxoStatusServices.getServiceCallHistory(reset),
|
|
94
|
+
getStatusForTxids: this.getStatusForTxidsServices.getServiceCallHistory(reset),
|
|
95
|
+
getScriptHashHistory: this.getScriptHashHistoryServices.getServiceCallHistory(reset),
|
|
96
|
+
updateFiatExchangeRates: this.updateFiatExchangeRateServices.getServiceCallHistory(reset)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
76
100
|
async getChainTracker(): Promise<ChainTracker> {
|
|
77
101
|
if (!this.options.chaintracks)
|
|
78
102
|
throw new sdk.WERR_INVALID_PARAMETER('options.chaintracks', `valid to enable 'getChainTracker' service.`)
|
|
@@ -123,11 +147,22 @@ export class Services implements sdk.WalletServices {
|
|
|
123
147
|
}
|
|
124
148
|
|
|
125
149
|
for (let tries = 0; tries < services.count; tries++) {
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
150
|
+
const stc = services.serviceToCall
|
|
151
|
+
try {
|
|
152
|
+
const r = await stc.service(txids)
|
|
153
|
+
if (r.status === 'success') {
|
|
154
|
+
services.addServiceCallSuccess(stc)
|
|
155
|
+
r0 = r
|
|
156
|
+
break
|
|
157
|
+
} else {
|
|
158
|
+
if (r.error)
|
|
159
|
+
services.addServiceCallError(stc, r.error)
|
|
160
|
+
else
|
|
161
|
+
services.addServiceCallFailure(stc)
|
|
162
|
+
}
|
|
163
|
+
} catch (eu: unknown) {
|
|
164
|
+
const e = sdk.WalletError.fromUnknown(eu)
|
|
165
|
+
services.addServiceCallError(stc, e)
|
|
131
166
|
}
|
|
132
167
|
services.next()
|
|
133
168
|
}
|
|
@@ -174,11 +209,22 @@ export class Services implements sdk.WalletServices {
|
|
|
174
209
|
|
|
175
210
|
for (let retry = 0; retry < 2; retry++) {
|
|
176
211
|
for (let tries = 0; tries < services.count; tries++) {
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
212
|
+
const stc = services.serviceToCall
|
|
213
|
+
try {
|
|
214
|
+
const r = await stc.service(output, outputFormat, outpoint)
|
|
215
|
+
if (r.status === 'success') {
|
|
216
|
+
services.addServiceCallSuccess(stc)
|
|
217
|
+
r0 = r
|
|
218
|
+
break
|
|
219
|
+
} else {
|
|
220
|
+
if (r.error)
|
|
221
|
+
services.addServiceCallError(stc, r.error)
|
|
222
|
+
else
|
|
223
|
+
services.addServiceCallFailure(stc)
|
|
224
|
+
}
|
|
225
|
+
} catch (eu: unknown) {
|
|
226
|
+
const e = sdk.WalletError.fromUnknown(eu)
|
|
227
|
+
services.addServiceCallError(stc, e)
|
|
182
228
|
}
|
|
183
229
|
services.next()
|
|
184
230
|
}
|
|
@@ -200,19 +246,27 @@ export class Services implements sdk.WalletServices {
|
|
|
200
246
|
}
|
|
201
247
|
|
|
202
248
|
for (let tries = 0; tries < services.count; tries++) {
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
249
|
+
const stc = services.serviceToCall
|
|
250
|
+
try {
|
|
251
|
+
const r = await stc.service(hash)
|
|
252
|
+
if (r.status === 'success') {
|
|
253
|
+
r0 = r
|
|
254
|
+
break
|
|
255
|
+
} else {
|
|
256
|
+
if (r.error)
|
|
257
|
+
services.addServiceCallError(stc, r.error)
|
|
258
|
+
else
|
|
259
|
+
services.addServiceCallFailure(stc)
|
|
260
|
+
}
|
|
261
|
+
} catch (eu: unknown) {
|
|
262
|
+
const e = sdk.WalletError.fromUnknown(eu)
|
|
263
|
+
services.addServiceCallError(stc, e)
|
|
208
264
|
}
|
|
209
265
|
services.next()
|
|
210
266
|
}
|
|
211
267
|
return r0
|
|
212
268
|
}
|
|
213
269
|
|
|
214
|
-
postBeefCount = 0
|
|
215
|
-
|
|
216
270
|
/**
|
|
217
271
|
*
|
|
218
272
|
* @param beef
|
|
@@ -220,15 +274,20 @@ export class Services implements sdk.WalletServices {
|
|
|
220
274
|
* @returns
|
|
221
275
|
*/
|
|
222
276
|
async postBeef(beef: Beef, txids: string[]): Promise<sdk.PostBeefResult[]> {
|
|
223
|
-
this.
|
|
224
|
-
const
|
|
225
|
-
for (let i = this.postBeefCount % services.length; i > 0; i--) {
|
|
226
|
-
// roll the array of services so the providers aren't always called in the same order.
|
|
227
|
-
services.unshift(services.pop()!)
|
|
228
|
-
}
|
|
277
|
+
const services = this.postBeefServices
|
|
278
|
+
const stcs = services.allServicesToCall
|
|
229
279
|
let rs = await Promise.all(
|
|
230
|
-
|
|
231
|
-
const r = await service(beef, txids)
|
|
280
|
+
stcs.map(async stc => {
|
|
281
|
+
const r = await stc.service(beef, txids)
|
|
282
|
+
if (r.status === 'success') {
|
|
283
|
+
services.addServiceCallSuccess(stc)
|
|
284
|
+
} else {
|
|
285
|
+
if (r.error) {
|
|
286
|
+
services.addServiceCallError(stc, r.error)
|
|
287
|
+
} else {
|
|
288
|
+
services.addServiceCallFailure(stc)
|
|
289
|
+
}
|
|
290
|
+
}
|
|
232
291
|
return r
|
|
233
292
|
})
|
|
234
293
|
)
|
|
@@ -236,31 +295,46 @@ export class Services implements sdk.WalletServices {
|
|
|
236
295
|
}
|
|
237
296
|
|
|
238
297
|
async getRawTx(txid: string, useNext?: boolean): Promise<sdk.GetRawTxResult> {
|
|
239
|
-
|
|
298
|
+
const services = this.getRawTxServices
|
|
299
|
+
if (useNext) services.next()
|
|
240
300
|
|
|
241
301
|
const r0: sdk.GetRawTxResult = { txid }
|
|
242
302
|
|
|
243
|
-
for (let tries = 0; tries <
|
|
244
|
-
const
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
303
|
+
for (let tries = 0; tries < services.count; tries++) {
|
|
304
|
+
const stc = services.serviceToCall
|
|
305
|
+
try {
|
|
306
|
+
const r = await stc.service(txid, this.chain)
|
|
307
|
+
if (r.rawTx) {
|
|
308
|
+
const hash = asString(doubleSha256BE(r.rawTx!))
|
|
309
|
+
// Confirm transaction hash matches txid
|
|
310
|
+
if (hash === asString(txid)) {
|
|
311
|
+
// If we have a match, call it done.
|
|
312
|
+
r0.rawTx = r.rawTx
|
|
313
|
+
r0.name = r.name
|
|
314
|
+
r0.error = undefined
|
|
315
|
+
services.addServiceCallSuccess(stc)
|
|
316
|
+
break
|
|
317
|
+
}
|
|
318
|
+
r.error = new sdk.WERR_INTERNAL(`computed txid ${hash} doesn't match requested value ${txid}`)
|
|
319
|
+
r.rawTx = undefined
|
|
255
320
|
}
|
|
256
|
-
r.error = new sdk.WERR_INTERNAL(`computed txid ${hash} doesn't match requested value ${txid}`)
|
|
257
|
-
r.rawTx = undefined
|
|
258
|
-
}
|
|
259
|
-
if (r.error && !r0.error && !r0.rawTx)
|
|
260
|
-
// If we have an error and didn't before...
|
|
261
|
-
r0.error = r.error
|
|
262
321
|
|
|
263
|
-
|
|
322
|
+
if (r.error)
|
|
323
|
+
services.addServiceCallError(stc, r.error)
|
|
324
|
+
else if (!r.rawTx)
|
|
325
|
+
services.addServiceCallSuccess(stc, `not found`)
|
|
326
|
+
else
|
|
327
|
+
services.addServiceCallFailure(stc)
|
|
328
|
+
|
|
329
|
+
if (r.error && !r0.error && !r0.rawTx)
|
|
330
|
+
// If we have an error and didn't before...
|
|
331
|
+
r0.error = r.error
|
|
332
|
+
|
|
333
|
+
} catch (eu: unknown) {
|
|
334
|
+
const e = sdk.WalletError.fromUnknown(eu)
|
|
335
|
+
services.addServiceCallError(stc, e)
|
|
336
|
+
}
|
|
337
|
+
services.next()
|
|
264
338
|
}
|
|
265
339
|
return r0
|
|
266
340
|
}
|
|
@@ -307,28 +381,41 @@ export class Services implements sdk.WalletServices {
|
|
|
307
381
|
}
|
|
308
382
|
|
|
309
383
|
async getMerklePath(txid: string, useNext?: boolean): Promise<sdk.GetMerklePathResult> {
|
|
310
|
-
|
|
384
|
+
const services = this.getMerklePathServices
|
|
385
|
+
if (useNext) services.next()
|
|
311
386
|
|
|
312
387
|
const r0: sdk.GetMerklePathResult = { notes: [] }
|
|
313
388
|
|
|
314
|
-
for (let tries = 0; tries <
|
|
315
|
-
const
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
389
|
+
for (let tries = 0; tries < services.count; tries++) {
|
|
390
|
+
const stc = services.serviceToCall
|
|
391
|
+
try {
|
|
392
|
+
const r = await stc.service(txid, this)
|
|
393
|
+
if (r.notes) r0.notes!.push(...r.notes)
|
|
394
|
+
if (!r0.name) r0.name = r.name
|
|
395
|
+
if (r.merklePath) {
|
|
396
|
+
// If we have a proof, call it done.
|
|
397
|
+
r0.merklePath = r.merklePath
|
|
398
|
+
r0.header = r.header
|
|
399
|
+
r0.name = r.name
|
|
400
|
+
r0.error = undefined
|
|
401
|
+
services.addServiceCallSuccess(stc)
|
|
402
|
+
break
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (r.error)
|
|
406
|
+
services.addServiceCallError(stc, r.error)
|
|
407
|
+
else
|
|
408
|
+
services.addServiceCallFailure(stc)
|
|
409
|
+
|
|
410
|
+
if (r.error && !r0.error) {
|
|
411
|
+
// If we have an error and didn't before...
|
|
412
|
+
r0.error = r.error
|
|
413
|
+
}
|
|
414
|
+
} catch (eu: unknown) {
|
|
415
|
+
const e = sdk.WalletError.fromUnknown(eu)
|
|
416
|
+
services.addServiceCallError(stc, e)
|
|
329
417
|
}
|
|
330
|
-
|
|
331
|
-
this.getMerklePathServices.next()
|
|
418
|
+
services.next()
|
|
332
419
|
}
|
|
333
420
|
return r0
|
|
334
421
|
}
|
|
@@ -350,16 +437,19 @@ export class Services implements sdk.WalletServices {
|
|
|
350
437
|
let r0: sdk.FiatExchangeRates | undefined
|
|
351
438
|
|
|
352
439
|
for (let tries = 0; tries < services.count; tries++) {
|
|
353
|
-
const
|
|
440
|
+
const stc = services.serviceToCall
|
|
354
441
|
try {
|
|
355
|
-
const r = await service(this.targetCurrencies, this.options)
|
|
442
|
+
const r = await stc.service(this.targetCurrencies, this.options)
|
|
356
443
|
if (this.targetCurrencies.every(c => typeof r.rates[c] === 'number')) {
|
|
444
|
+
services.addServiceCallSuccess(stc)
|
|
357
445
|
r0 = r
|
|
358
446
|
break
|
|
447
|
+
} else {
|
|
448
|
+
services.addServiceCallFailure(stc)
|
|
359
449
|
}
|
|
360
450
|
} catch (eu: unknown) {
|
|
361
451
|
const e = sdk.WalletError.fromUnknown(eu)
|
|
362
|
-
|
|
452
|
+
services.addServiceCallError(stc, e)
|
|
363
453
|
}
|
|
364
454
|
services.next()
|
|
365
455
|
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { _tu, logger } from '../../../test/utils/TestUtilsWalletStorage'
|
|
2
|
+
import { sdk, wait } from '../../index.client'
|
|
3
|
+
import { ARC } from '../providers/ARC'
|
|
4
|
+
import { Beef, BeefTx } from '@bsv/sdk'
|
|
5
|
+
import { arcDefaultUrl, arcGorillaPoolUrl } from '../createDefaultWalletServicesOptions'
|
|
6
|
+
import { Setup } from '../../index.all'
|
|
7
|
+
|
|
8
|
+
describe('ArcGorillaPool tests', () => {
|
|
9
|
+
jest.setTimeout(99999999)
|
|
10
|
+
|
|
11
|
+
const env = _tu.getEnv('main')
|
|
12
|
+
const arc = new ARC(arcGorillaPoolUrl(env.chain)!, {
|
|
13
|
+
apiKey: ''
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
test.skip('0 double spend', async () => {
|
|
17
|
+
const beef = Beef.fromString(testnetDoubleSpendBeef)
|
|
18
|
+
const txids = [beef.txs.slice(-1)[0].txid]
|
|
19
|
+
const r = await arc.postBeef(beef, txids)
|
|
20
|
+
expect(r.status === 'error').toBe(true)
|
|
21
|
+
expect(r.txidResults[0].doubleSpend).toBe(true)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test.skip('1 postRawTx', async () => {
|
|
25
|
+
const r = await postRawTxTest('main', arc)
|
|
26
|
+
logger(`2 postBeef mainnet done ${r}`)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('2 postBeef', async () => {
|
|
30
|
+
const r = await postBeefTest('main', arc)
|
|
31
|
+
logger(`2 postBeef mainnet done ${r}`)
|
|
32
|
+
})
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
async function postBeefTest(chain: sdk.Chain, arc: ARC): Promise<string> {
|
|
36
|
+
if (Setup.noEnv(chain)) return 'skipped'
|
|
37
|
+
const c = await _tu.createNoSendTxPair(chain)
|
|
38
|
+
|
|
39
|
+
const txids = [c.txidDo, c.txidUndo]
|
|
40
|
+
|
|
41
|
+
const r = await arc.postBeef(c.beef, txids)
|
|
42
|
+
expect(r.status).toBe('success')
|
|
43
|
+
for (const txid of txids) {
|
|
44
|
+
const tr = r.txidResults.find(tx => tx.txid === txid)
|
|
45
|
+
expect(tr).not.toBeUndefined()
|
|
46
|
+
expect(tr!.status).toBe('success')
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// replace Undo transaction with double spend transaction and send again.
|
|
50
|
+
const beef2 = c.beef.clone()
|
|
51
|
+
beef2.txs[beef2.txs.length - 1] = BeefTx.fromTx(c.doubleSpendTx)
|
|
52
|
+
const txids2 = [c.txidDo, c.doubleSpendTx.id('hex')]
|
|
53
|
+
|
|
54
|
+
const r2 = await arc.postBeef(beef2, txids2)
|
|
55
|
+
expect(r2.status).toBe('error')
|
|
56
|
+
for (const txid of txids2) {
|
|
57
|
+
const tr = r2.txidResults.find(tx => tx.txid === txid)
|
|
58
|
+
expect(tr).not.toBeUndefined()
|
|
59
|
+
if (txid === c.txidDo) {
|
|
60
|
+
expect(tr!.status).toBe('success')
|
|
61
|
+
} else {
|
|
62
|
+
expect(tr!.status).toBe('error')
|
|
63
|
+
expect(tr!.doubleSpend).toBe(true)
|
|
64
|
+
expect(tr!.competingTxs).toEqual([c.txidUndo])
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return 'passed'
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function postRawTxTest(chain: sdk.Chain, arc: ARC): Promise<void> {
|
|
71
|
+
if (Setup.noEnv(chain)) return
|
|
72
|
+
const c = await _tu.createNoSendTxPair(chain)
|
|
73
|
+
|
|
74
|
+
const rawTxDo = c.beef.findTxid(c.txidDo)!.tx!.toHex()
|
|
75
|
+
const rawTxUndo = c.beef.findTxid(c.txidUndo)!.tx!.toHex()
|
|
76
|
+
|
|
77
|
+
const rDo = await arc.postRawTx(rawTxDo)
|
|
78
|
+
expect(rDo.status).toBe('success')
|
|
79
|
+
expect(rDo.txid).toBe(c.txidDo)
|
|
80
|
+
|
|
81
|
+
await wait(1000)
|
|
82
|
+
|
|
83
|
+
const rUndo = await arc.postRawTx(rawTxUndo)
|
|
84
|
+
expect(rUndo.status).toBe('success')
|
|
85
|
+
expect(rUndo.txid).toBe(c.txidUndo)
|
|
86
|
+
expect(rUndo.doubleSpend).not.toBe(true)
|
|
87
|
+
|
|
88
|
+
await wait(1000)
|
|
89
|
+
|
|
90
|
+
{
|
|
91
|
+
// Send same transaction again...
|
|
92
|
+
const rUndo = await arc.postRawTx(rawTxUndo)
|
|
93
|
+
expect(rUndo.status).toBe('success')
|
|
94
|
+
expect(rUndo.txid).toBe(c.txidUndo)
|
|
95
|
+
expect(rUndo.doubleSpend).not.toBe(true)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
await wait(1000)
|
|
99
|
+
|
|
100
|
+
// Confirm double spend detection.
|
|
101
|
+
const rDouble = await arc.postRawTx(c.doubleSpendTx.toHex())
|
|
102
|
+
expect(rDouble.status).toBe('error')
|
|
103
|
+
expect(rDouble.doubleSpend).toBe(true)
|
|
104
|
+
expect(rDouble.competingTxs![0]).toBe(c.txidUndo)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const testnetDoubleSpendBeef =
|
|
108
|
+
'0100beef01fe65631900020200009df812619ae232d2363d91516ab3e811211192933526bbc2aee71b54ccb236d10102462876eec65d9aa26d957421c5cc8dd9119b61177242b9dd814fb190fd0a361801010076a3297928f6841bcb656e91225540e87c65f67d8ec12bc768d7656eb7561b3d02010000000159617a9d17562f7c9765e5dfa6a9a393aa2809ca6166a3d7a31c09efcc5070141f0000006a47304402200a528145a67ba1879b88a093cb711f79f04413a81d5678f314302e36a7f59e43022010bc4bb3c2574052c50bbdc8a05c31fb39e69280656b34f5dc22e2ceadc3bb4a412102fd4200bf389d16479b3d06f97fee0752f2c3b9dc29fb3ddce2b327d851b8902bffffffff0204000000000000001976a9140df1a69c834bb7d9bb5b2b7d6a34e5a401db3e1688ac01000000000000001976a91423f2562a8092ed24eddc77c74387b44c561692a188ac0000000001000100000001462876eec65d9aa26d957421c5cc8dd9119b61177242b9dd814fb190fd0a3618000000006a47304402204183bbfdcf11d50907b91f5e70ea8f81228501ce84e24af75c8d984682d094dc022029caa8f7e5acb4990bbeafee523a3c4a99b78e98b9e5c41349147b099679d4ae412103b76389eea6494c2c30443cba9d59b9dba05fb04e467bc94272629615b87a429fffffffff0202000000000000001976a91476d851e59fcb4ee0ebe6947496db3a393b08e49c88ac01000000000000001976a91423f2562a8092ed24eddc77c74387b44c561692a188ac0000000000'
|
|
@@ -2,10 +2,15 @@ import { randomBytesHex, sdk } from '../index.client'
|
|
|
2
2
|
import { ChaintracksServiceClient } from './chaintracker'
|
|
3
3
|
|
|
4
4
|
export function createDefaultWalletServicesOptions(chain: sdk.Chain): sdk.WalletServicesOptions {
|
|
5
|
+
const deploymentId = `wallet-toolbox-${randomBytesHex(16)}`
|
|
5
6
|
const taalApiKey =
|
|
6
7
|
chain === 'main'
|
|
7
8
|
? 'mainnet_9596de07e92300c6287e4393594ae39c' // no plan
|
|
8
9
|
: 'testnet_0e6cf72133b43ea2d7861da2a38684e3' // personal "starter" key
|
|
10
|
+
const gorillaPoolApiKey =
|
|
11
|
+
chain === 'main'
|
|
12
|
+
? ''
|
|
13
|
+
: ''
|
|
9
14
|
|
|
10
15
|
const o: sdk.WalletServicesOptions = {
|
|
11
16
|
chain,
|
|
@@ -36,7 +41,12 @@ export function createDefaultWalletServicesOptions(chain: sdk.Chain): sdk.Wallet
|
|
|
36
41
|
arcUrl: arcDefaultUrl(chain),
|
|
37
42
|
arcConfig: {
|
|
38
43
|
apiKey: taalApiKey,
|
|
39
|
-
deploymentId
|
|
44
|
+
deploymentId
|
|
45
|
+
},
|
|
46
|
+
arcGorillaPoolUrl: arcGorillaPoolUrl(chain),
|
|
47
|
+
arcGorillaPoolConfig: {
|
|
48
|
+
apiKey: gorillaPoolApiKey,
|
|
49
|
+
deploymentId
|
|
40
50
|
}
|
|
41
51
|
}
|
|
42
52
|
return o
|
|
@@ -46,3 +56,8 @@ export function arcDefaultUrl(chain: sdk.Chain): string {
|
|
|
46
56
|
const url = chain === 'main' ? 'https://arc.taal.com' : 'https://arc-test.taal.com'
|
|
47
57
|
return url
|
|
48
58
|
}
|
|
59
|
+
|
|
60
|
+
export function arcGorillaPoolUrl(chain: sdk.Chain): string | undefined {
|
|
61
|
+
const url = chain === 'main' ? 'https://arc.gorillapool.io' : undefined
|
|
62
|
+
return url
|
|
63
|
+
}
|
|
@@ -36,6 +36,7 @@ function defaultDeploymentId(): string {
|
|
|
36
36
|
* Represents an ARC transaction broadcaster.
|
|
37
37
|
*/
|
|
38
38
|
export class ARC {
|
|
39
|
+
readonly name: string
|
|
39
40
|
readonly URL: string
|
|
40
41
|
readonly apiKey: string | undefined
|
|
41
42
|
readonly deploymentId: string
|
|
@@ -50,16 +51,17 @@ export class ARC {
|
|
|
50
51
|
* @param {string} URL - The URL endpoint for the ARC API.
|
|
51
52
|
* @param {ArcConfig} config - Configuration options for the ARC broadcaster.
|
|
52
53
|
*/
|
|
53
|
-
constructor(URL: string, config?: ArcConfig)
|
|
54
|
+
constructor(URL: string, config?: ArcConfig, name?: string)
|
|
54
55
|
/**
|
|
55
56
|
* Constructs an instance of the ARC broadcaster.
|
|
56
57
|
*
|
|
57
58
|
* @param {string} URL - The URL endpoint for the ARC API.
|
|
58
59
|
* @param {string} apiKey - The API key used for authorization with the ARC API.
|
|
59
60
|
*/
|
|
60
|
-
constructor(URL: string, apiKey?: string)
|
|
61
|
+
constructor(URL: string, apiKey?: string, name?: string)
|
|
61
62
|
|
|
62
|
-
constructor(URL: string, config?: string | ArcConfig) {
|
|
63
|
+
constructor(URL: string, config?: string | ArcConfig, name?: string) {
|
|
64
|
+
this.name = name ?? 'ARC'
|
|
63
65
|
this.URL = URL
|
|
64
66
|
if (typeof config === 'string') {
|
|
65
67
|
this.apiKey = config
|
|
@@ -143,7 +145,7 @@ export class ARC {
|
|
|
143
145
|
}
|
|
144
146
|
|
|
145
147
|
const url = `${this.URL}/v1/tx`
|
|
146
|
-
const nn = () => ({ name:
|
|
148
|
+
const nn = () => ({ name: this.name, when: new Date().toISOString() })
|
|
147
149
|
const nne = () => ({ ...nn(), rawTx, txids: txids.join(','), url })
|
|
148
150
|
|
|
149
151
|
try {
|
|
@@ -241,13 +243,13 @@ export class ARC {
|
|
|
241
243
|
*/
|
|
242
244
|
async postBeef(beef: Beef, txids: string[]): Promise<sdk.PostBeefResult> {
|
|
243
245
|
const r: sdk.PostBeefResult = {
|
|
244
|
-
name:
|
|
246
|
+
name: this.name,
|
|
245
247
|
status: 'success',
|
|
246
248
|
txidResults: [],
|
|
247
249
|
notes: []
|
|
248
250
|
}
|
|
249
251
|
|
|
250
|
-
const nn = () => ({ name:
|
|
252
|
+
const nn = () => ({ name: this.name, when: new Date().toISOString() })
|
|
251
253
|
|
|
252
254
|
if (beef.version === BEEF_V2 && beef.txs.every(btx => !btx.isTxidOnly)) {
|
|
253
255
|
beef.version = BEEF_V1
|
|
@@ -89,25 +89,15 @@ export async function internalizeAction(
|
|
|
89
89
|
// TODO: Add support for known txids...
|
|
90
90
|
|
|
91
91
|
const txValid = await ab.verify(await wallet.getServices().getChainTracker(), false)
|
|
92
|
-
if (!txValid || !ab.atomicTxid)
|
|
92
|
+
if (!txValid || !ab.atomicTxid) {
|
|
93
|
+
console.log(`internalizeAction beef is invalid: ${ab.toLogString()}`)
|
|
94
|
+
throw new sdk.WERR_INVALID_PARAMETER('tx', 'valid AtomicBEEF')
|
|
95
|
+
}
|
|
93
96
|
const txid = ab.atomicTxid
|
|
94
97
|
const btx = ab.findTxid(txid)
|
|
95
98
|
if (!btx) throw new sdk.WERR_INVALID_PARAMETER('tx', `valid AtomicBEEF with newest txid of ${txid}`)
|
|
96
99
|
const tx = btx.tx!
|
|
97
100
|
|
|
98
|
-
/*
|
|
99
|
-
for (const i of tx.inputs) {
|
|
100
|
-
if (!i.sourceTXID)
|
|
101
|
-
throw new sdk.WERR_INTERNAL('beef Transactions must have sourceTXIDs')
|
|
102
|
-
if (!i.sourceTransaction) {
|
|
103
|
-
const btx = ab.findTxid(i.sourceTXID)
|
|
104
|
-
if (!btx)
|
|
105
|
-
throw new sdk.WERR_INVALID_PARAMETER('tx', `valid AtomicBEEF and contain input transaction with txid ${i.sourceTXID}`);
|
|
106
|
-
i.sourceTransaction = btx.tx
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
*/
|
|
110
|
-
|
|
111
101
|
return { ab, tx, txid }
|
|
112
102
|
}
|
|
113
103
|
}
|
|
@@ -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 {
|
|
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
|
/**
|
|
@@ -488,6 +489,27 @@ export class StorageKnex extends StorageProvider implements sdk.WalletStoragePro
|
|
|
488
489
|
let q = this.toDb(args.trx)<T>(table)
|
|
489
490
|
if (args.partial && Object.keys(args.partial).length > 0) q.where(args.partial)
|
|
490
491
|
if (args.since) q.where('updated_at', '>=', this.validateDateForWhere(args.since))
|
|
492
|
+
if (args.orderDescending) {
|
|
493
|
+
let sortColumn = ''
|
|
494
|
+
switch (table) {
|
|
495
|
+
case 'certificates': sortColumn = 'certificateId'; break
|
|
496
|
+
case 'commissions': sortColumn = 'commissionId'; break
|
|
497
|
+
case 'output_baskets': sortColumn = 'basketId'; break
|
|
498
|
+
case 'outputs': sortColumn = 'outputId'; break
|
|
499
|
+
case 'output_tags': sortColumn = 'outputTagId'; break
|
|
500
|
+
case 'proven_tx_reqs': sortColumn = 'provenTxReqId'; break
|
|
501
|
+
case 'proven_txs': sortColumn = 'provenTxId'; break
|
|
502
|
+
case 'sync_states': sortColumn = 'syncStateId'; break
|
|
503
|
+
case 'transactions': sortColumn = 'transactionId'; break
|
|
504
|
+
case 'tx_labels': sortColumn = 'txLabelId'; break
|
|
505
|
+
case 'users': sortColumn = 'userId'; break
|
|
506
|
+
case 'monitor_events': sortColumn = 'id'; break
|
|
507
|
+
default: break;
|
|
508
|
+
}
|
|
509
|
+
if (sortColumn !== '') {
|
|
510
|
+
q.orderBy(sortColumn, 'desc')
|
|
511
|
+
}
|
|
512
|
+
}
|
|
491
513
|
if (args.paged) {
|
|
492
514
|
q.limit(args.paged.limit)
|
|
493
515
|
q.offset(args.paged.offset || 0)
|
|
@@ -554,7 +576,10 @@ export class StorageKnex extends StorageProvider implements sdk.WalletStoragePro
|
|
|
554
576
|
)
|
|
555
577
|
const q = this.setupQuery('proven_tx_reqs', args)
|
|
556
578
|
if (args.status && args.status.length > 0) q.whereIn('status', args.status)
|
|
557
|
-
if (args.txids
|
|
579
|
+
if (args.txids) {
|
|
580
|
+
const txids = args.txids.filter(txid => txid !== undefined)
|
|
581
|
+
if (txids.length > 0) q.whereIn('txid', txids)
|
|
582
|
+
}
|
|
558
583
|
return q
|
|
559
584
|
}
|
|
560
585
|
findProvenTxsQuery(args: sdk.FindProvenTxsArgs): Knex.QueryBuilder {
|
|
@@ -1128,9 +1153,13 @@ export class StorageKnex extends StorageProvider implements sdk.WalletStoragePro
|
|
|
1128
1153
|
return entities
|
|
1129
1154
|
}
|
|
1130
1155
|
|
|
1131
|
-
async adminStats(adminIdentityKey: string): Promise<
|
|
1156
|
+
async adminStats(adminIdentityKey: string): Promise<AdminStatsResult> {
|
|
1132
1157
|
if (this.dbtype !== 'MySQL') throw new sdk.WERR_NOT_IMPLEMENTED('adminStats, only MySQL is supported')
|
|
1133
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
|
+
|
|
1134
1163
|
const one_day_ago = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString()
|
|
1135
1164
|
const one_week_ago = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString()
|
|
1136
1165
|
const one_month_ago = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString()
|
|
@@ -1271,7 +1300,9 @@ select
|
|
|
1271
1300
|
(select count(*) from output_tags where created_at > '${one_month_ago}') as tagsMonth,
|
|
1272
1301
|
(select count(*) from output_tags) as tagsTotal
|
|
1273
1302
|
`)
|
|
1274
|
-
const r:
|
|
1303
|
+
const r: AdminStatsResult = {
|
|
1304
|
+
monitorStats,
|
|
1305
|
+
servicesStats,
|
|
1275
1306
|
requestedBy: adminIdentityKey,
|
|
1276
1307
|
when: new Date().toISOString(),
|
|
1277
1308
|
usersDay,
|