@psf/bch-js 5.3.0 → 5.4.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 +5 -7
- package/src/bch-js.js +0 -2
- package/src/psf-slp-indexer.js +13 -11
- package/src/utxo.js +12 -2
- package/test/integration/chains/bchn/psf-slp-indexer.integration.js +12 -1
- package/test/integration/chains/bchn/utxo-integration.js +19 -17
- package/test/unit/utxo-unit.js +7 -0
- package/src/ipfs.js +0 -454
- package/test/unit/ipfs.js +0 -443
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@psf/bch-js",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.4.0",
|
|
4
4
|
"description": "The FullStack.cash JavaScript library for Bitcoin Cash and SLP Tokens",
|
|
5
5
|
"author": "Chris Troutner <chris.troutner@gmail.com>",
|
|
6
6
|
"contributors": [
|
|
@@ -37,13 +37,11 @@
|
|
|
37
37
|
"url": "git+https://github.com/Permissionless-Software-Foundation/bch-js.git"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@psf/bip21": "2.0.1",
|
|
41
40
|
"@chris.troutner/bip32-utils": "1.0.5",
|
|
41
|
+
"@psf/bip21": "2.0.1",
|
|
42
42
|
"@psf/bitcoincash-ops": "2.0.0",
|
|
43
43
|
"@psf/bitcoincashjs-lib": "4.0.2",
|
|
44
44
|
"@psf/coininfo": "4.0.0",
|
|
45
|
-
"@uppy/core": "1.10.4",
|
|
46
|
-
"@uppy/tus": "1.5.12",
|
|
47
45
|
"axios": "^0.21.4",
|
|
48
46
|
"bc-bip68": "1.0.5",
|
|
49
47
|
"bchaddrjs-slp": "0.2.5",
|
|
@@ -65,7 +63,7 @@
|
|
|
65
63
|
"wif": "2.0.6"
|
|
66
64
|
},
|
|
67
65
|
"devDependencies": {
|
|
68
|
-
"apidoc": "0.
|
|
66
|
+
"apidoc": "^0.50.5",
|
|
69
67
|
"assert": "2.0.0",
|
|
70
68
|
"chai": "4.1.2",
|
|
71
69
|
"coveralls": "3.0.2",
|
|
@@ -77,10 +75,10 @@
|
|
|
77
75
|
"eslint-plugin-standard": "4.0.0",
|
|
78
76
|
"husky": "^4.3.8",
|
|
79
77
|
"lodash.clonedeep": "4.5.0",
|
|
80
|
-
"mocha": "9.1
|
|
78
|
+
"mocha": "^9.2.1",
|
|
81
79
|
"node-mocks-http": "1.7.0",
|
|
82
80
|
"nyc": "15.1.0",
|
|
83
|
-
"semantic-release": "
|
|
81
|
+
"semantic-release": "^19.0.2",
|
|
84
82
|
"sinon": "9.2.2",
|
|
85
83
|
"standard": "^16.0.4"
|
|
86
84
|
},
|
package/src/bch-js.js
CHANGED
|
@@ -28,7 +28,6 @@ const Script = require('./script')
|
|
|
28
28
|
const Price = require('./price')
|
|
29
29
|
const Schnorr = require('./schnorr')
|
|
30
30
|
const SLP = require('./slp/slp')
|
|
31
|
-
const IPFS = require('./ipfs')
|
|
32
31
|
const Encryption = require('./encryption')
|
|
33
32
|
const Utxo = require('./utxo')
|
|
34
33
|
const Transaction = require('./transaction')
|
|
@@ -111,7 +110,6 @@ class BCHJS {
|
|
|
111
110
|
this.SLP = new SLP(libConfig)
|
|
112
111
|
this.SLP.HDNode = this.HDNode
|
|
113
112
|
|
|
114
|
-
this.IPFS = new IPFS()
|
|
115
113
|
this.Utxo = new Utxo(libConfig)
|
|
116
114
|
this.Transaction = new Transaction(libConfig)
|
|
117
115
|
|
package/src/psf-slp-indexer.js
CHANGED
|
@@ -41,7 +41,7 @@ class PsfSlpIndexer {
|
|
|
41
41
|
this.rawTransaction = new RawTransaction(config)
|
|
42
42
|
this.slpUtils = new SlpUtils(config)
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
// _this = this
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/**
|
|
@@ -53,8 +53,8 @@ class PsfSlpIndexer {
|
|
|
53
53
|
* @apiExample Example usage:
|
|
54
54
|
* (async () => {
|
|
55
55
|
* try {
|
|
56
|
-
* let status = await bchjs.PsfSlpIndexer.status()
|
|
57
|
-
* console.log(status)
|
|
56
|
+
* let status = await bchjs.PsfSlpIndexer.status()
|
|
57
|
+
* console.log(status)
|
|
58
58
|
* } catch(error) {
|
|
59
59
|
* console.error(error)
|
|
60
60
|
* }
|
|
@@ -91,8 +91,8 @@ class PsfSlpIndexer {
|
|
|
91
91
|
* @apiExample Example usage:
|
|
92
92
|
* (async () => {
|
|
93
93
|
* try {
|
|
94
|
-
* let balance = await bchjs.PsfSlpIndexer.balance('bitcoincash:qzmd5vxgh9m22m6fgvm57yd6kjnjl9qnwywsf3583n')
|
|
95
|
-
* console.log(balance)
|
|
94
|
+
* let balance = await bchjs.PsfSlpIndexer.balance('bitcoincash:qzmd5vxgh9m22m6fgvm57yd6kjnjl9qnwywsf3583n')
|
|
95
|
+
* console.log(balance)
|
|
96
96
|
* } catch(error) {
|
|
97
97
|
* console.error(error)
|
|
98
98
|
* }
|
|
@@ -155,12 +155,14 @@ class PsfSlpIndexer {
|
|
|
155
155
|
* @apiName Token Stats
|
|
156
156
|
* @apiGroup PSF SLP
|
|
157
157
|
* @apiDescription Return list stats for a single slp token.
|
|
158
|
+
* The second input is a Boolean, which determins the the transaction history
|
|
159
|
+
* of the token is included in the returned data. The default is false.
|
|
158
160
|
*
|
|
159
161
|
* @apiExample Example usage:
|
|
160
162
|
* (async () => {
|
|
161
163
|
* try {
|
|
162
|
-
* let tokenStats = await bchjs.PsfSlpIndexer.tokenStats('a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2')
|
|
163
|
-
* console.log(tokenStats)
|
|
164
|
+
* let tokenStats = await bchjs.PsfSlpIndexer.tokenStats('a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2', true)
|
|
165
|
+
* console.log(tokenStats)
|
|
164
166
|
* } catch(error) {
|
|
165
167
|
* console.error(error)
|
|
166
168
|
* }
|
|
@@ -194,13 +196,13 @@ class PsfSlpIndexer {
|
|
|
194
196
|
*
|
|
195
197
|
*/
|
|
196
198
|
|
|
197
|
-
async tokenStats (tokenId) {
|
|
199
|
+
async tokenStats (tokenId, withTxHistory = false) {
|
|
198
200
|
try {
|
|
199
201
|
// Handle single address.
|
|
200
202
|
if (typeof tokenId === 'string') {
|
|
201
203
|
const response = await axios.post(
|
|
202
204
|
`${this.restURL}psf/slp/token`,
|
|
203
|
-
{ tokenId },
|
|
205
|
+
{ tokenId, withTxHistory },
|
|
204
206
|
this.axiosOptions
|
|
205
207
|
)
|
|
206
208
|
return response.data
|
|
@@ -221,8 +223,8 @@ class PsfSlpIndexer {
|
|
|
221
223
|
* @apiExample Example usage:
|
|
222
224
|
* (async () => {
|
|
223
225
|
* try {
|
|
224
|
-
* let txData = await bchjs.PsfSlpIndexer.tx('a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2')
|
|
225
|
-
* console.log(txData)
|
|
226
|
+
* let txData = await bchjs.PsfSlpIndexer.tx('a4fb5c2da1aa064e25018a43f9165040071d9e984ba190c222a7f59053af84b2')
|
|
227
|
+
* console.log(txData)
|
|
226
228
|
* } catch(error) {
|
|
227
229
|
* console.error(error)
|
|
228
230
|
* }
|
package/src/utxo.js
CHANGED
|
@@ -404,8 +404,18 @@ class UTXO {
|
|
|
404
404
|
if (!thisUtxo.isSlp) {
|
|
405
405
|
thisUtxo.txid = thisUtxo.tx_hash
|
|
406
406
|
thisUtxo.vout = thisUtxo.tx_pos
|
|
407
|
-
thisUtxo.isSlp = false
|
|
408
407
|
thisUtxo.address = addr
|
|
408
|
+
|
|
409
|
+
// Check the transaction to see if its a 'null' token, ignored by
|
|
410
|
+
// the indexer.
|
|
411
|
+
const txData = await this.psfSlpIndexer.tx(thisUtxo.tx_hash)
|
|
412
|
+
// console.log(`txData: ${JSON.stringify(txData, null, 2)}`)
|
|
413
|
+
if (txData.txData.isValidSlp === null) {
|
|
414
|
+
thisUtxo.isSlp = null
|
|
415
|
+
} else {
|
|
416
|
+
thisUtxo.isSlp = false
|
|
417
|
+
}
|
|
418
|
+
// console.log(`thisUtxo.isSlp: ${thisUtxo.isSlp}`)
|
|
409
419
|
}
|
|
410
420
|
}
|
|
411
421
|
|
|
@@ -438,7 +448,7 @@ class UTXO {
|
|
|
438
448
|
|
|
439
449
|
return outObj
|
|
440
450
|
} catch (err) {
|
|
441
|
-
|
|
451
|
+
console.error('Error in bchjs.Utxo.get(): ', err)
|
|
442
452
|
|
|
443
453
|
if (err.error) throw new Error(err.error)
|
|
444
454
|
throw err
|
|
@@ -40,13 +40,24 @@ describe('#psf-slp-indexer', () => {
|
|
|
40
40
|
})
|
|
41
41
|
|
|
42
42
|
describe('#tokenStats', () => {
|
|
43
|
-
it('should get stats on a token', async () => {
|
|
43
|
+
it('should get stats on a token, without tx history', async () => {
|
|
44
44
|
const tokenId =
|
|
45
45
|
'38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0'
|
|
46
46
|
|
|
47
47
|
const result = await bchjs.PsfSlpIndexer.tokenStats(tokenId)
|
|
48
48
|
// console.log('result: ', result)
|
|
49
49
|
|
|
50
|
+
assert.property(result.tokenData, 'documentUri')
|
|
51
|
+
assert.property(result.tokenData, 'totalBurned')
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('should get stats on a token, with tx history', async () => {
|
|
55
|
+
const tokenId =
|
|
56
|
+
'38e97c5d7d3585a2cbf3f9580c82ca33985f9cb0845d4dcce220cb709f9538b0'
|
|
57
|
+
|
|
58
|
+
const result = await bchjs.PsfSlpIndexer.tokenStats(tokenId, true)
|
|
59
|
+
// console.log('result: ', result)
|
|
60
|
+
|
|
50
61
|
assert.property(result.tokenData, 'documentUri')
|
|
51
62
|
assert.property(result.tokenData, 'txs')
|
|
52
63
|
assert.property(result.tokenData, 'totalBurned')
|
|
@@ -6,6 +6,7 @@ const assert = require('chai').assert
|
|
|
6
6
|
|
|
7
7
|
const BCHJS = require('../../../../src/bch-js')
|
|
8
8
|
const bchjs = new BCHJS()
|
|
9
|
+
// const bchjs = new BCHJS({ restURL: 'http://192.168.2.129:3000/v5/' })
|
|
9
10
|
|
|
10
11
|
describe('#UTXO', () => {
|
|
11
12
|
beforeEach(async () => {
|
|
@@ -125,43 +126,35 @@ describe('#UTXO', () => {
|
|
|
125
126
|
it('should hydrate token UTXOs', async () => {
|
|
126
127
|
const utxos = [
|
|
127
128
|
{
|
|
128
|
-
txid:
|
|
129
|
-
'384e1b8197e8de7d38f98317af2cf5f6bcb50007c46943b3498a6fab6e8aeb7c',
|
|
129
|
+
txid: '384e1b8197e8de7d38f98317af2cf5f6bcb50007c46943b3498a6fab6e8aeb7c',
|
|
130
130
|
vout: 1,
|
|
131
131
|
type: 'token',
|
|
132
132
|
qty: '10000000',
|
|
133
|
-
tokenId:
|
|
134
|
-
'a436c8e1b6bee3d701c6044d190f76f774be83c36de8d34a988af4489e86dd37',
|
|
133
|
+
tokenId: 'a436c8e1b6bee3d701c6044d190f76f774be83c36de8d34a988af4489e86dd37',
|
|
135
134
|
address: 'bitcoincash:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvg8nfhq4m'
|
|
136
135
|
},
|
|
137
136
|
{
|
|
138
|
-
txid:
|
|
139
|
-
'4fc789405d58ec612c69eba29aa56cf0c7f228349801114138424eb68df4479d',
|
|
137
|
+
txid: '4fc789405d58ec612c69eba29aa56cf0c7f228349801114138424eb68df4479d',
|
|
140
138
|
vout: 1,
|
|
141
139
|
type: 'token',
|
|
142
140
|
qty: '100000000',
|
|
143
|
-
tokenId:
|
|
144
|
-
'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb',
|
|
141
|
+
tokenId: 'df808a41672a0a0ae6475b44f272a107bc9961b90f29dc918d71301f24fe92fb',
|
|
145
142
|
address: 'bitcoincash:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvg8nfhq4m'
|
|
146
143
|
},
|
|
147
144
|
{
|
|
148
|
-
txid:
|
|
149
|
-
'42054bba4d69bfe7801ece0cffc754194b04239034fdfe9dbe321ef76c9a2d93',
|
|
145
|
+
txid: '42054bba4d69bfe7801ece0cffc754194b04239034fdfe9dbe321ef76c9a2d93',
|
|
150
146
|
vout: 5,
|
|
151
147
|
type: 'token',
|
|
152
148
|
qty: '4764',
|
|
153
|
-
tokenId:
|
|
154
|
-
'f05faf13a29c7f5e54ab921750aafb6afaa953db863bd2cf432e918661d4132f',
|
|
149
|
+
tokenId: 'f05faf13a29c7f5e54ab921750aafb6afaa953db863bd2cf432e918661d4132f',
|
|
155
150
|
address: 'bitcoincash:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvg8nfhq4m'
|
|
156
151
|
},
|
|
157
152
|
{
|
|
158
|
-
txid:
|
|
159
|
-
'06938d0a0d15aa76524ffe61fe111d6d2b2ea9dd8dcd4c7c7744614ced370861',
|
|
153
|
+
txid: '06938d0a0d15aa76524ffe61fe111d6d2b2ea9dd8dcd4c7c7744614ced370861',
|
|
160
154
|
vout: 5,
|
|
161
155
|
type: 'token',
|
|
162
156
|
qty: '238',
|
|
163
|
-
tokenId:
|
|
164
|
-
'f05faf13a29c7f5e54ab921750aafb6afaa953db863bd2cf432e918661d4132f',
|
|
157
|
+
tokenId: 'f05faf13a29c7f5e54ab921750aafb6afaa953db863bd2cf432e918661d4132f',
|
|
165
158
|
address: 'bitcoincash:qzv3zz2trz0xgp6a96lu4m6vp2nkwag0kvg8nfhq4m'
|
|
166
159
|
}
|
|
167
160
|
]
|
|
@@ -199,7 +192,7 @@ describe('#UTXO', () => {
|
|
|
199
192
|
|
|
200
193
|
// TODO: NFTs are currently not identified as different than normal BCH UTXOs.
|
|
201
194
|
// The psf-slp-indexer needs to be updated to fix this issue.
|
|
202
|
-
it('should handle
|
|
195
|
+
it('should handle minting batons', async () => {
|
|
203
196
|
const addr = 'simpleledger:qrm0c67wwqh0w7wjxua2gdt2xggnm90xwsr5k22euj'
|
|
204
197
|
|
|
205
198
|
const result = await bchjs.Utxo.get(addr)
|
|
@@ -218,6 +211,15 @@ describe('#UTXO', () => {
|
|
|
218
211
|
assert.isAbove(result.bchUtxos.length, 0)
|
|
219
212
|
assert.equal(result.slpUtxos.type1.tokens.length, 0)
|
|
220
213
|
})
|
|
214
|
+
|
|
215
|
+
it('should handle Group NFTs', async () => {
|
|
216
|
+
const addr = 'bitcoincash:qrnghwrfgccf3s5e9wnglzxegcnhje9rkcwv2eka33'
|
|
217
|
+
|
|
218
|
+
const result = await bchjs.Utxo.get(addr)
|
|
219
|
+
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
220
|
+
|
|
221
|
+
assert.equal(result.nullUtxos.length, 0)
|
|
222
|
+
})
|
|
221
223
|
})
|
|
222
224
|
})
|
|
223
225
|
|
package/test/unit/utxo-unit.js
CHANGED
|
@@ -249,6 +249,10 @@ describe('#utxo', () => {
|
|
|
249
249
|
sandbox
|
|
250
250
|
.stub(bchjs.Utxo.psfSlpIndexer, 'balance')
|
|
251
251
|
.resolves(mockData.psfSlpIndexerUtxos01)
|
|
252
|
+
sandbox
|
|
253
|
+
.stub(bchjs.Utxo.psfSlpIndexer, 'tx')
|
|
254
|
+
.resolves({ txData: { isValidSlp: false } })
|
|
255
|
+
|
|
252
256
|
// Mock function to return the same input. Good enough for this test.
|
|
253
257
|
sandbox.stub(bchjs.Utxo, 'hydrateTokenData').resolves(x => x)
|
|
254
258
|
|
|
@@ -278,6 +282,9 @@ describe('#utxo', () => {
|
|
|
278
282
|
sandbox
|
|
279
283
|
.stub(bchjs.Utxo.electrumx, 'utxo')
|
|
280
284
|
.resolves(mockData.fulcrumUtxos02)
|
|
285
|
+
sandbox
|
|
286
|
+
.stub(bchjs.Utxo.psfSlpIndexer, 'tx')
|
|
287
|
+
.resolves({ txData: { isValidSlp: false } })
|
|
281
288
|
|
|
282
289
|
// Force psf-slp-indexer to return no UTXOs
|
|
283
290
|
sandbox
|
package/src/ipfs.js
DELETED
|
@@ -1,454 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
This library interacts with the IPFS REST API at FullStack.cash for uploading
|
|
3
|
-
and downloading data from the IPFS network.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const axios = require('axios')
|
|
7
|
-
const Uppy = require('@uppy/core')
|
|
8
|
-
const Tus = require('@uppy/tus')
|
|
9
|
-
const fs = require('fs')
|
|
10
|
-
|
|
11
|
-
let _this
|
|
12
|
-
|
|
13
|
-
class IPFS {
|
|
14
|
-
constructor (config) {
|
|
15
|
-
this.IPFS_API = process.env.IPFS_API
|
|
16
|
-
? process.env.IPFS_API
|
|
17
|
-
: 'https://ipfs-file-upload.fullstackcash.nl'
|
|
18
|
-
// : `http://localhost:5001`
|
|
19
|
-
|
|
20
|
-
// Default options when calling axios.
|
|
21
|
-
this.axiosOptions = {
|
|
22
|
-
headers: {
|
|
23
|
-
// authorization: `Token ${this.apiToken}`,
|
|
24
|
-
timeout: 15000 // Timeout if the server does not respond in time.
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
_this = this
|
|
29
|
-
|
|
30
|
-
_this.axios = axios
|
|
31
|
-
_this.fs = fs
|
|
32
|
-
|
|
33
|
-
// Initialize Uppy
|
|
34
|
-
_this.uppy = _this.initUppy()
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Initializes Uppy, which is used for file uploads.
|
|
38
|
-
initUppy () {
|
|
39
|
-
const uppy = Uppy({
|
|
40
|
-
allowMultipleUploads: false,
|
|
41
|
-
meta: { test: 'avatar' },
|
|
42
|
-
debug: false,
|
|
43
|
-
restrictions: {
|
|
44
|
-
maxFileSize: null,
|
|
45
|
-
maxNumberOfFiles: 1,
|
|
46
|
-
minNumberOfFiles: 1,
|
|
47
|
-
allowedFileTypes: null // type of files allowed to load
|
|
48
|
-
}
|
|
49
|
-
})
|
|
50
|
-
uppy.use(Tus, { endpoint: `${_this.IPFS_API}/uppy-files` })
|
|
51
|
-
|
|
52
|
-
return uppy
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* @api IPFS.createFileModelServer() createFileModelServer()
|
|
57
|
-
* @apiName createFileModelServer()
|
|
58
|
-
* @apiGroup IPFS
|
|
59
|
-
* @apiDescription Creates a new model on the server. If successful, will
|
|
60
|
-
* return an object with file data. That object contains a BCH address,
|
|
61
|
-
* payment amount, and _id required to be able to upload a file.
|
|
62
|
-
*
|
|
63
|
-
* @apiExample Example usage:
|
|
64
|
-
* (async () => {
|
|
65
|
-
* try {
|
|
66
|
-
* const path = `${__dirname}/ipfs.js`
|
|
67
|
-
* let fileData = await bchjs.IPFS.createFileModelServer(path);
|
|
68
|
-
* console.log(fileData);
|
|
69
|
-
* } catch(error) {
|
|
70
|
-
* console.error(error)
|
|
71
|
-
* }
|
|
72
|
-
* })()
|
|
73
|
-
*
|
|
74
|
-
* {
|
|
75
|
-
* "success": true,
|
|
76
|
-
* "hostingCostBCH": 0.00004197,
|
|
77
|
-
* "hostingCostUSD": 0.01,
|
|
78
|
-
* "file": {
|
|
79
|
-
* "payloadLink": "",
|
|
80
|
-
* "hasBeenPaid": false,
|
|
81
|
-
* "_id": "5ec562319bfacc745e8d8a52",
|
|
82
|
-
* "schemaVersion": 1,
|
|
83
|
-
* "size": 4458,
|
|
84
|
-
* "fileName": "ipfs.js",
|
|
85
|
-
* "fileExtension": "js",
|
|
86
|
-
* "createdTimestamp": "1589994033.655",
|
|
87
|
-
* "hostingCost": 4196,
|
|
88
|
-
* "walletIndex": 49,
|
|
89
|
-
* "bchAddr": "bchtest:qzrpkevu7h2ayfa4rjx08r5elvpfu72dg567x3mh3c",
|
|
90
|
-
* "__v": 0
|
|
91
|
-
* }
|
|
92
|
-
*/
|
|
93
|
-
async createFileModelServer (path) {
|
|
94
|
-
try {
|
|
95
|
-
// Ensure the file exists.
|
|
96
|
-
if (!_this.fs.existsSync(path)) {
|
|
97
|
-
throw new Error(`Could not find this file: ${path}`)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Read in the file.
|
|
101
|
-
const fileBuf = _this.fs.readFileSync(path)
|
|
102
|
-
// console.log(`fileBuf: `, fileBuf)
|
|
103
|
-
|
|
104
|
-
// console.log(`Buffer length: ${fileBuf.length}`)
|
|
105
|
-
|
|
106
|
-
// Get the file name from the path.
|
|
107
|
-
const splitPath = path.split('/')
|
|
108
|
-
const fileName = splitPath[splitPath.length - 1]
|
|
109
|
-
|
|
110
|
-
// Get the file extension.
|
|
111
|
-
const splitExt = fileName.split('.')
|
|
112
|
-
const fileExt = splitExt[splitExt.length - 1]
|
|
113
|
-
|
|
114
|
-
const fileObj = {
|
|
115
|
-
schemaVersion: 1,
|
|
116
|
-
size: fileBuf.length,
|
|
117
|
-
fileName: fileName,
|
|
118
|
-
fileExtension: fileExt
|
|
119
|
-
}
|
|
120
|
-
// console.log(`fileObj: ${JSON.stringify(fileObj, null, 2)}`)
|
|
121
|
-
|
|
122
|
-
const fileData = await _this.axios.post(`${this.IPFS_API}/files`, {
|
|
123
|
-
file: fileObj
|
|
124
|
-
})
|
|
125
|
-
// console.log(`fileData.data: ${JSON.stringify(fileData.data, null, 2)}`)
|
|
126
|
-
|
|
127
|
-
return fileData.data
|
|
128
|
-
} catch (err) {
|
|
129
|
-
console.error('Error in createFileModel()')
|
|
130
|
-
throw err
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* @api IPFS.uploadFileServer() uploadFileServer()
|
|
136
|
-
* @apiName uploadFile()
|
|
137
|
-
* @apiGroup IPFS
|
|
138
|
-
* @apiDescription Upload a file to the FullStack.cash IPFS server. If
|
|
139
|
-
* successful, it will return an object with an ID, a BCH address, and an
|
|
140
|
-
* amount of BCH to pay.
|
|
141
|
-
*
|
|
142
|
-
* @apiExample Example usage:
|
|
143
|
-
* (async () => {
|
|
144
|
-
* try {
|
|
145
|
-
* const path = `${__dirname}/ipfs.js`
|
|
146
|
-
* let fileData = await bchjs.IPFS.uploadFileServer(path, "5ec562319bfacc745e8d8a52");
|
|
147
|
-
* console.log(fileData);
|
|
148
|
-
* } catch(error) {
|
|
149
|
-
* console.error(error)
|
|
150
|
-
* }
|
|
151
|
-
* })()
|
|
152
|
-
*
|
|
153
|
-
* {
|
|
154
|
-
* "schemaVersion": 1,
|
|
155
|
-
* "size": 2374,
|
|
156
|
-
* "fileId": "5ec562319bfacc745e8d8a52",
|
|
157
|
-
* "fileName": "ipfs.js",
|
|
158
|
-
* "fileExtension": "js"
|
|
159
|
-
* }
|
|
160
|
-
*/
|
|
161
|
-
async uploadFileServer (path, modelId) {
|
|
162
|
-
try {
|
|
163
|
-
// Ensure the file exists.
|
|
164
|
-
if (!_this.fs.existsSync(path)) {
|
|
165
|
-
throw new Error(`Could not find this file: ${path}`)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (!modelId) {
|
|
169
|
-
throw new Error(
|
|
170
|
-
'Must include a file model ID in order to upload a file.'
|
|
171
|
-
)
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// Read in the file.
|
|
175
|
-
const fileBuf = _this.fs.readFileSync(path)
|
|
176
|
-
|
|
177
|
-
// Get the file name from the path.
|
|
178
|
-
const splitPath = path.split('/')
|
|
179
|
-
const fileName = splitPath[splitPath.length - 1]
|
|
180
|
-
|
|
181
|
-
// Prepare the upload object. Get a file ID from Uppy.
|
|
182
|
-
const id = _this.uppy.addFile({
|
|
183
|
-
name: fileName,
|
|
184
|
-
data: fileBuf,
|
|
185
|
-
source: 'Local',
|
|
186
|
-
isRemote: false
|
|
187
|
-
})
|
|
188
|
-
// console.log(`id: ${JSON.stringify(id, null, 2)}`)
|
|
189
|
-
|
|
190
|
-
// Add the model ID, required to be allowed to upload the file.
|
|
191
|
-
_this.uppy.setFileMeta(id, { fileModelId: modelId })
|
|
192
|
-
|
|
193
|
-
// Upload the file to the server.
|
|
194
|
-
const upData = await _this.uppy.upload()
|
|
195
|
-
|
|
196
|
-
if (upData.failed.length) {
|
|
197
|
-
throw new Error('The file could not be uploaded')
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (upData.successful.length) {
|
|
201
|
-
delete upData.successful[0].data
|
|
202
|
-
// console.log(`upData: ${JSON.stringify(upData, null, 2)}`)
|
|
203
|
-
|
|
204
|
-
const fileObj = {
|
|
205
|
-
schemaVersion: 1,
|
|
206
|
-
size: upData.successful[0].progress.bytesTotal,
|
|
207
|
-
fileId: upData.successful[0].meta.fileModelId,
|
|
208
|
-
fileName: upData.successful[0].name,
|
|
209
|
-
fileExtension: upData.successful[0].extension
|
|
210
|
-
}
|
|
211
|
-
// console.log(`fileObj: ${JSON.stringify(fileObj, null, 2)}`)
|
|
212
|
-
|
|
213
|
-
return fileObj
|
|
214
|
-
// return true
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
return false
|
|
218
|
-
} catch (err) {
|
|
219
|
-
console.error('Error in bch-js/src/ipfs.js/upload(): ')
|
|
220
|
-
throw err
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* @api IPFS.getStatus() getStatus()
|
|
226
|
-
* @apiName getStatus()
|
|
227
|
-
* @apiGroup IPFS
|
|
228
|
-
* @apiDescription Gets the status of the uploaded file. Will return an object
|
|
229
|
-
* that indicates the payment status. If the file is paid, it should contain
|
|
230
|
-
* an IPFS hash.
|
|
231
|
-
*
|
|
232
|
-
* @apiExample Example usage:
|
|
233
|
-
* (async () => {
|
|
234
|
-
* try {
|
|
235
|
-
* const modelId = "5ec7392c2acfe57aa62e945a"
|
|
236
|
-
* let fileData = await bchjs.IPFS.getStatus(modelId)
|
|
237
|
-
* console.log(fileData)
|
|
238
|
-
* } catch(error) {
|
|
239
|
-
* console.error(error)
|
|
240
|
-
* }
|
|
241
|
-
* })()
|
|
242
|
-
*
|
|
243
|
-
* {
|
|
244
|
-
* "hasBeenPaid": true,
|
|
245
|
-
* "satCost": 4403,
|
|
246
|
-
* "bchAddr": "bchtest:qz5z82u0suqh80x5tfx4ht8kdrkkw664vcy44uz0wk",
|
|
247
|
-
* "ipfsHash": "QmRDHPhY5hCNVRMVQvS2H9uty8P1skdwgLaHpUAkEvsjcE",
|
|
248
|
-
* "fileId": "5ec7392c2acfe57aa62e945a",
|
|
249
|
-
* "fileName": "ipfs-e2e.js"
|
|
250
|
-
* }
|
|
251
|
-
*/
|
|
252
|
-
async getStatus (modelId) {
|
|
253
|
-
try {
|
|
254
|
-
if (!modelId) throw new Error('Must include a file model ID.')
|
|
255
|
-
|
|
256
|
-
const fileData = await _this.axios.get(
|
|
257
|
-
`${this.IPFS_API}/files/${modelId}`
|
|
258
|
-
)
|
|
259
|
-
// console.log(`fileData.data: ${JSON.stringify(fileData.data, null, 2)}`)
|
|
260
|
-
|
|
261
|
-
const fileObj = {
|
|
262
|
-
hasBeenPaid: fileData.data.file.hasBeenPaid,
|
|
263
|
-
satCost: fileData.data.file.hostingCost,
|
|
264
|
-
bchAddr: fileData.data.file.bchAddr,
|
|
265
|
-
ipfsHash: fileData.data.file.payloadLink,
|
|
266
|
-
fileId: fileData.data.file._id,
|
|
267
|
-
fileName: fileData.data.file.fileName
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
return fileObj
|
|
271
|
-
} catch (err) {
|
|
272
|
-
console.error('Error in getStatus()')
|
|
273
|
-
throw err
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* @api IPFS.createFileModelWeb() createFileModelWeb()
|
|
279
|
-
* @apiName createFileModelWeb()
|
|
280
|
-
* @apiGroup IPFS
|
|
281
|
-
* @apiDescription Creates a new model on the server. If successful, will
|
|
282
|
-
* return an object with file data. That object contains a BCH address,
|
|
283
|
-
* payment amount, and _id required to be able to upload a file.
|
|
284
|
-
*
|
|
285
|
-
* @apiExample Example usage:
|
|
286
|
-
* (async () => {
|
|
287
|
-
* try {
|
|
288
|
-
* const content = ['PSF']
|
|
289
|
-
* const name = 'psf.txt' // Content can be Array , ArrayBuffer , Blob
|
|
290
|
-
* const options = { type: "text/plain" }
|
|
291
|
-
* const file = new File(content,name,options)
|
|
292
|
-
* let fileData = await bchjs.IPFS.createFileModelWeb(file);
|
|
293
|
-
* console.log(fileData);
|
|
294
|
-
* } catch(error) {
|
|
295
|
-
* console.error(error)
|
|
296
|
-
* }
|
|
297
|
-
* })()
|
|
298
|
-
*
|
|
299
|
-
* {
|
|
300
|
-
* "success": true,
|
|
301
|
-
* "hostingCostBCH": 0.00004197,
|
|
302
|
-
* "hostingCostUSD": 0.01,
|
|
303
|
-
* "file": {
|
|
304
|
-
* "payloadLink": "",
|
|
305
|
-
* "hasBeenPaid": false,
|
|
306
|
-
* "_id": "5ec562319bfacc745e8d8a52",
|
|
307
|
-
* "schemaVersion": 1,
|
|
308
|
-
* "size": 4458,
|
|
309
|
-
* "fileName": "ipfs.js",
|
|
310
|
-
* "fileExtension": "js",
|
|
311
|
-
* "createdTimestamp": "1589994033.655",
|
|
312
|
-
* "hostingCost": 4196,
|
|
313
|
-
* "walletIndex": 49,
|
|
314
|
-
* "bchAddr": "bchtest:qzrpkevu7h2ayfa4rjx08r5elvpfu72dg567x3mh3c",
|
|
315
|
-
* "__v": 0
|
|
316
|
-
* }
|
|
317
|
-
*/
|
|
318
|
-
async createFileModelWeb (file) {
|
|
319
|
-
try {
|
|
320
|
-
if (!file) throw new Error('File is required')
|
|
321
|
-
|
|
322
|
-
const { name, size } = file
|
|
323
|
-
|
|
324
|
-
if (!name || typeof name !== 'string') {
|
|
325
|
-
throw new Error("File should have the property 'name' of string type")
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
if (!size || typeof size !== 'number') {
|
|
329
|
-
throw new Error("File should have the property 'size' of number type")
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// Get the file extension.
|
|
333
|
-
const splitExt = name.split('.')
|
|
334
|
-
const fileExt = splitExt[splitExt.length - 1]
|
|
335
|
-
|
|
336
|
-
const fileObj = {
|
|
337
|
-
schemaVersion: 1,
|
|
338
|
-
size: size,
|
|
339
|
-
fileName: name,
|
|
340
|
-
fileExtension: fileExt
|
|
341
|
-
}
|
|
342
|
-
// console.log(`fileObj: ${JSON.stringify(fileObj, null, 2)}`)
|
|
343
|
-
|
|
344
|
-
const fileData = await _this.axios.post(`${this.IPFS_API}/files`, {
|
|
345
|
-
file: fileObj
|
|
346
|
-
})
|
|
347
|
-
// console.log(`fileData.data: ${JSON.stringify(fileData.data, null, 2)}`)
|
|
348
|
-
|
|
349
|
-
return fileData.data
|
|
350
|
-
} catch (err) {
|
|
351
|
-
console.error('Error in createFileModelWeb()')
|
|
352
|
-
throw err
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* @api IPFS.uploadFileWeb() uploadFileWeb()
|
|
358
|
-
* @apiName uploadFileWeb()
|
|
359
|
-
* @apiGroup IPFS
|
|
360
|
-
* @apiDescription Upload a file to the FullStack.cash IPFS server. If
|
|
361
|
-
* successful, it will return an object with an ID, a BCH address, and an
|
|
362
|
-
* amount of BCH to pay.
|
|
363
|
-
*
|
|
364
|
-
* @apiExample Example usage:
|
|
365
|
-
* (async () => {
|
|
366
|
-
* try {
|
|
367
|
-
* * const content = ['PSF']
|
|
368
|
-
* const name = 'psf.txt' // Content can be Array , ArrayBuffer , Blob
|
|
369
|
-
* const options = { type: "text/plain" }
|
|
370
|
-
* const file = new File(content,name,options)
|
|
371
|
-
* let fileData = await bchjs.IPFS.uploadFile(file, "5ec562319bfacc745e8d8a52");
|
|
372
|
-
* console.log(fileData);
|
|
373
|
-
* } catch(error) {
|
|
374
|
-
* console.error(error)
|
|
375
|
-
* }
|
|
376
|
-
* })()
|
|
377
|
-
*
|
|
378
|
-
* {
|
|
379
|
-
* "schemaVersion": 1,
|
|
380
|
-
* "size": 2374,
|
|
381
|
-
* "fileId": "5ec562319bfacc745e8d8a52",
|
|
382
|
-
* "fileName": "ipfs.js",
|
|
383
|
-
* "fileExtension": "js"
|
|
384
|
-
* }
|
|
385
|
-
*/
|
|
386
|
-
async uploadFileWeb (file, modelId) {
|
|
387
|
-
try {
|
|
388
|
-
if (!file) throw new Error('File is required')
|
|
389
|
-
|
|
390
|
-
const { name, type, size } = file
|
|
391
|
-
|
|
392
|
-
if (!name || typeof name !== 'string') {
|
|
393
|
-
throw new Error("File should have the property 'name' of string type")
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
if (!type || typeof type !== 'string') {
|
|
397
|
-
throw new Error("File should have the property 'type' of string type")
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
if (!size || typeof size !== 'number') {
|
|
401
|
-
throw new Error("File should have the property 'size' of number type")
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
if (!modelId) {
|
|
405
|
-
throw new Error(
|
|
406
|
-
'Must include a file model ID in order to upload a file.'
|
|
407
|
-
)
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// Prepare the upload object. Get a file ID from Uppy.
|
|
411
|
-
const id = _this.uppy.addFile({
|
|
412
|
-
name: name,
|
|
413
|
-
data: file,
|
|
414
|
-
source: 'Local',
|
|
415
|
-
isRemote: false
|
|
416
|
-
})
|
|
417
|
-
// console.log(`id: ${JSON.stringify(id, null, 2)}`)
|
|
418
|
-
|
|
419
|
-
// Add the model ID, required to be allowed to upload the file.
|
|
420
|
-
_this.uppy.setFileMeta(id, { fileModelId: modelId })
|
|
421
|
-
|
|
422
|
-
// Upload the file to the server.
|
|
423
|
-
const upData = await _this.uppy.upload()
|
|
424
|
-
|
|
425
|
-
if (upData.failed.length) {
|
|
426
|
-
throw new Error('The file could not be uploaded')
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
if (upData.successful.length) {
|
|
430
|
-
delete upData.successful[0].data
|
|
431
|
-
// console.log(`upData: ${JSON.stringify(upData, null, 2)}`)
|
|
432
|
-
|
|
433
|
-
const fileObj = {
|
|
434
|
-
schemaVersion: 1,
|
|
435
|
-
size: upData.successful[0].progress.bytesTotal,
|
|
436
|
-
fileId: upData.successful[0].meta.fileModelId,
|
|
437
|
-
fileName: upData.successful[0].name,
|
|
438
|
-
fileExtension: upData.successful[0].extension
|
|
439
|
-
}
|
|
440
|
-
// console.log(`fileObj: ${JSON.stringify(fileObj, null, 2)}`)
|
|
441
|
-
|
|
442
|
-
return fileObj
|
|
443
|
-
// return true
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
return false
|
|
447
|
-
} catch (err) {
|
|
448
|
-
console.error('Error in bch-js/src/ipfs.js/uploadFileWeb(): ')
|
|
449
|
-
throw err
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
module.exports = IPFS
|
package/test/unit/ipfs.js
DELETED
|
@@ -1,443 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Unit tests for the IPFS Class.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
const assert = require('chai').assert
|
|
6
|
-
const sinon = require('sinon')
|
|
7
|
-
const BCHJS = require('../../src/bch-js')
|
|
8
|
-
let bchjs
|
|
9
|
-
|
|
10
|
-
const mockData = require('./fixtures/ipfs-mock')
|
|
11
|
-
|
|
12
|
-
describe('#IPFS', () => {
|
|
13
|
-
let sandbox
|
|
14
|
-
|
|
15
|
-
beforeEach(() => {
|
|
16
|
-
sandbox = sinon.createSandbox()
|
|
17
|
-
|
|
18
|
-
bchjs = new BCHJS()
|
|
19
|
-
})
|
|
20
|
-
|
|
21
|
-
afterEach(() => sandbox.restore())
|
|
22
|
-
|
|
23
|
-
describe('#initUppy', () => {
|
|
24
|
-
it('should initialize uppy', () => {
|
|
25
|
-
bchjs.IPFS.initUppy()
|
|
26
|
-
})
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
describe('#createFileModelServer', () => {
|
|
30
|
-
it('should throw an error if file does not exist', async () => {
|
|
31
|
-
try {
|
|
32
|
-
const path = '/non-existant-file'
|
|
33
|
-
|
|
34
|
-
await bchjs.IPFS.createFileModelServer(path)
|
|
35
|
-
|
|
36
|
-
assert.equal(true, false, 'Unexpected result')
|
|
37
|
-
} catch (err) {
|
|
38
|
-
// console.log(`err.message: ${err.message}`)
|
|
39
|
-
assert.include(err.message, 'Could not find this file')
|
|
40
|
-
}
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
it('should create a new file model', async () => {
|
|
44
|
-
const path = `${__dirname.toString()}/ipfs.js`
|
|
45
|
-
|
|
46
|
-
sandbox
|
|
47
|
-
.stub(bchjs.IPFS.axios, 'post')
|
|
48
|
-
.resolves({ data: mockData.mockNewFileModel })
|
|
49
|
-
|
|
50
|
-
const result = await bchjs.IPFS.createFileModelServer(path)
|
|
51
|
-
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
52
|
-
|
|
53
|
-
assert.property(result, 'success')
|
|
54
|
-
assert.equal(result.success, true)
|
|
55
|
-
|
|
56
|
-
assert.property(result, 'hostingCostBCH')
|
|
57
|
-
assert.property(result, 'hostingCostUSD')
|
|
58
|
-
assert.property(result, 'file')
|
|
59
|
-
|
|
60
|
-
assert.property(result.file, 'payloadLink')
|
|
61
|
-
assert.property(result.file, 'hasBeenPaid')
|
|
62
|
-
assert.property(result.file, '_id')
|
|
63
|
-
assert.property(result.file, 'schemaVersion')
|
|
64
|
-
assert.property(result.file, 'size')
|
|
65
|
-
assert.property(result.file, 'fileName')
|
|
66
|
-
assert.property(result.file, 'fileExtension')
|
|
67
|
-
assert.property(result.file, 'createdTimestamp')
|
|
68
|
-
assert.property(result.file, 'hostingCost')
|
|
69
|
-
assert.property(result.file, 'walletIndex')
|
|
70
|
-
assert.property(result.file, 'bchAddr')
|
|
71
|
-
})
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
describe('#uploadFileServer', () => {
|
|
75
|
-
it('should throw an error if file does not exist', async () => {
|
|
76
|
-
try {
|
|
77
|
-
const path = '/non-existant-file'
|
|
78
|
-
|
|
79
|
-
await bchjs.IPFS.uploadFileServer(path)
|
|
80
|
-
|
|
81
|
-
assert.equal(true, false, 'Unexpected result')
|
|
82
|
-
} catch (err) {
|
|
83
|
-
// console.log(`err.message: ${err.message}`)
|
|
84
|
-
assert.include(err.message, 'Could not find this file')
|
|
85
|
-
}
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
it('should throw an error if modelId is not included', async () => {
|
|
89
|
-
try {
|
|
90
|
-
const path = `${__dirname.toString()}/ipfs.js`
|
|
91
|
-
|
|
92
|
-
await bchjs.IPFS.uploadFileServer(path)
|
|
93
|
-
|
|
94
|
-
assert.equal(true, false, 'Unexpected result')
|
|
95
|
-
} catch (err) {
|
|
96
|
-
// console.log(`err.message: ${err.message}`)
|
|
97
|
-
assert.include(err.message, 'Must include a file model ID')
|
|
98
|
-
}
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
it('Should throw error if the file was not uploaded', async () => {
|
|
102
|
-
try {
|
|
103
|
-
const mock = {
|
|
104
|
-
successful: [],
|
|
105
|
-
failed: [
|
|
106
|
-
{
|
|
107
|
-
id: 'file id'
|
|
108
|
-
}
|
|
109
|
-
]
|
|
110
|
-
}
|
|
111
|
-
sandbox.stub(bchjs.IPFS.uppy, 'upload').resolves(mock)
|
|
112
|
-
|
|
113
|
-
const path = `${__dirname.toString()}/ipfs.js`
|
|
114
|
-
await bchjs.IPFS.uploadFileServer(path, '5ec562319bfacc745e8d8a52')
|
|
115
|
-
|
|
116
|
-
assert.equal(true, false, 'Unexpected result')
|
|
117
|
-
} catch (err) {
|
|
118
|
-
// console.log(err)
|
|
119
|
-
assert.include(err.message, 'The file could not be uploaded')
|
|
120
|
-
}
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
it('should return file object if the file is uploaded', async () => {
|
|
124
|
-
try {
|
|
125
|
-
sandbox.stub(bchjs.IPFS.uppy, 'upload').resolves(mockData.uploadData)
|
|
126
|
-
|
|
127
|
-
const path = `${__dirname.toString()}/ipfs.js`
|
|
128
|
-
const result = await bchjs.IPFS.uploadFileServer(
|
|
129
|
-
path,
|
|
130
|
-
'5ec562319bfacc745e8d8a52'
|
|
131
|
-
)
|
|
132
|
-
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
133
|
-
|
|
134
|
-
assert.property(result, 'schemaVersion')
|
|
135
|
-
assert.property(result, 'size')
|
|
136
|
-
assert.property(result, 'fileId')
|
|
137
|
-
assert.property(result, 'fileName')
|
|
138
|
-
assert.property(result, 'fileExtension')
|
|
139
|
-
} catch (err) {
|
|
140
|
-
// console.log(err)
|
|
141
|
-
assert.equal(true, false, 'Unexpected result')
|
|
142
|
-
}
|
|
143
|
-
})
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
describe('#getStatus', () => {
|
|
147
|
-
it('should throw an error if modelId is not included', async () => {
|
|
148
|
-
try {
|
|
149
|
-
await bchjs.IPFS.getStatus()
|
|
150
|
-
|
|
151
|
-
assert.equal(true, false, 'Unexpected result')
|
|
152
|
-
} catch (err) {
|
|
153
|
-
// console.log(`err.message: ${err.message}`)
|
|
154
|
-
assert.include(err.message, 'Must include a file model ID')
|
|
155
|
-
}
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
it('should get data on an unpaid file', async () => {
|
|
159
|
-
const modelId = '5ec7392c2acfe57aa62e945a'
|
|
160
|
-
|
|
161
|
-
sandbox
|
|
162
|
-
.stub(bchjs.IPFS.axios, 'get')
|
|
163
|
-
.resolves({ data: mockData.unpaidFileData })
|
|
164
|
-
|
|
165
|
-
const result = await bchjs.IPFS.getStatus(modelId)
|
|
166
|
-
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
167
|
-
|
|
168
|
-
assert.property(result, 'hasBeenPaid')
|
|
169
|
-
assert.property(result, 'satCost')
|
|
170
|
-
assert.property(result, 'bchAddr')
|
|
171
|
-
assert.property(result, 'ipfsHash')
|
|
172
|
-
assert.property(result, 'fileId')
|
|
173
|
-
assert.property(result, 'fileName')
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
it('should get data on an unpaid file', async () => {
|
|
177
|
-
const modelId = '5ec7392c2acfe57aa62e945a'
|
|
178
|
-
|
|
179
|
-
sandbox
|
|
180
|
-
.stub(bchjs.IPFS.axios, 'get')
|
|
181
|
-
.resolves({ data: mockData.paidFileData })
|
|
182
|
-
|
|
183
|
-
const result = await bchjs.IPFS.getStatus(modelId)
|
|
184
|
-
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
185
|
-
|
|
186
|
-
assert.property(result, 'hasBeenPaid')
|
|
187
|
-
assert.property(result, 'satCost')
|
|
188
|
-
assert.property(result, 'bchAddr')
|
|
189
|
-
assert.property(result, 'ipfsHash')
|
|
190
|
-
assert.property(result, 'fileId')
|
|
191
|
-
assert.property(result, 'fileName')
|
|
192
|
-
})
|
|
193
|
-
})
|
|
194
|
-
|
|
195
|
-
describe('#createFileModelWeb', () => {
|
|
196
|
-
it('should throw an error if file is undefined', async () => {
|
|
197
|
-
try {
|
|
198
|
-
let file
|
|
199
|
-
|
|
200
|
-
await bchjs.IPFS.createFileModelWeb(file)
|
|
201
|
-
|
|
202
|
-
assert.equal(true, false, 'Unexpected result')
|
|
203
|
-
} catch (err) {
|
|
204
|
-
// console.log(`err.message: ${err.message}`)
|
|
205
|
-
assert.include(err.message, 'File is required')
|
|
206
|
-
}
|
|
207
|
-
})
|
|
208
|
-
it('should throw an error if file is empty', async () => {
|
|
209
|
-
try {
|
|
210
|
-
const file = {}
|
|
211
|
-
|
|
212
|
-
await bchjs.IPFS.createFileModelWeb(file)
|
|
213
|
-
|
|
214
|
-
assert.equal(true, false, 'Unexpected result')
|
|
215
|
-
} catch (err) {
|
|
216
|
-
// console.log(`err.message: ${err.message}`)
|
|
217
|
-
assert.include(
|
|
218
|
-
err.message,
|
|
219
|
-
'File should have the property \'name\' of string type'
|
|
220
|
-
)
|
|
221
|
-
}
|
|
222
|
-
})
|
|
223
|
-
it("should throw an error if 'name' property is not included", async () => {
|
|
224
|
-
try {
|
|
225
|
-
const file = {
|
|
226
|
-
size: 5000
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
await bchjs.IPFS.createFileModelWeb(file)
|
|
230
|
-
|
|
231
|
-
assert.equal(true, false, 'Unexpected result')
|
|
232
|
-
} catch (err) {
|
|
233
|
-
// console.log(`err.message: ${err.message}`)
|
|
234
|
-
assert.include(
|
|
235
|
-
err.message,
|
|
236
|
-
'File should have the property \'name\' of string type'
|
|
237
|
-
)
|
|
238
|
-
}
|
|
239
|
-
})
|
|
240
|
-
|
|
241
|
-
it("should throw an error if 'size' property is not included", async () => {
|
|
242
|
-
try {
|
|
243
|
-
const file = {
|
|
244
|
-
name: 'ipfs.js'
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
await bchjs.IPFS.createFileModelWeb(file)
|
|
248
|
-
|
|
249
|
-
assert.equal(true, false, 'Unexpected result')
|
|
250
|
-
} catch (err) {
|
|
251
|
-
// console.log(`err.message: ${err.message}`)
|
|
252
|
-
assert.include(
|
|
253
|
-
err.message,
|
|
254
|
-
'File should have the property \'size\' of number type'
|
|
255
|
-
)
|
|
256
|
-
}
|
|
257
|
-
})
|
|
258
|
-
|
|
259
|
-
it('should create a new file model', async () => {
|
|
260
|
-
const file = {
|
|
261
|
-
name: 'ipfs.js',
|
|
262
|
-
size: 5000,
|
|
263
|
-
type: 'text/plain'
|
|
264
|
-
}
|
|
265
|
-
sandbox
|
|
266
|
-
.stub(bchjs.IPFS.axios, 'post')
|
|
267
|
-
.resolves({ data: mockData.mockNewFileModel })
|
|
268
|
-
|
|
269
|
-
const result = await bchjs.IPFS.createFileModelWeb(file)
|
|
270
|
-
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
271
|
-
|
|
272
|
-
assert.property(result, 'success')
|
|
273
|
-
assert.equal(result.success, true)
|
|
274
|
-
|
|
275
|
-
assert.property(result, 'hostingCostBCH')
|
|
276
|
-
assert.property(result, 'hostingCostUSD')
|
|
277
|
-
assert.property(result, 'file')
|
|
278
|
-
|
|
279
|
-
assert.property(result.file, 'payloadLink')
|
|
280
|
-
assert.property(result.file, 'hasBeenPaid')
|
|
281
|
-
assert.property(result.file, '_id')
|
|
282
|
-
assert.property(result.file, 'schemaVersion')
|
|
283
|
-
assert.property(result.file, 'size')
|
|
284
|
-
assert.property(result.file, 'fileName')
|
|
285
|
-
assert.property(result.file, 'fileExtension')
|
|
286
|
-
assert.property(result.file, 'createdTimestamp')
|
|
287
|
-
assert.property(result.file, 'hostingCost')
|
|
288
|
-
assert.property(result.file, 'walletIndex')
|
|
289
|
-
assert.property(result.file, 'bchAddr')
|
|
290
|
-
})
|
|
291
|
-
})
|
|
292
|
-
|
|
293
|
-
describe('#uploadFileWeb', () => {
|
|
294
|
-
it('should throw an error if file is undefined', async () => {
|
|
295
|
-
try {
|
|
296
|
-
let file
|
|
297
|
-
|
|
298
|
-
await bchjs.IPFS.uploadFileWeb(file)
|
|
299
|
-
|
|
300
|
-
assert.equal(true, false, 'Unexpected result')
|
|
301
|
-
} catch (err) {
|
|
302
|
-
// console.log(`err.message: ${err.message}`)
|
|
303
|
-
assert.include(err.message, 'File is required')
|
|
304
|
-
}
|
|
305
|
-
})
|
|
306
|
-
it('should throw an error if file is empty', async () => {
|
|
307
|
-
try {
|
|
308
|
-
const file = {}
|
|
309
|
-
|
|
310
|
-
await bchjs.IPFS.uploadFileWeb(file)
|
|
311
|
-
|
|
312
|
-
assert.equal(true, false, 'Unexpected result')
|
|
313
|
-
} catch (err) {
|
|
314
|
-
// console.log(`err.message: ${err.message}`)
|
|
315
|
-
assert.include(
|
|
316
|
-
err.message,
|
|
317
|
-
'File should have the property \'name\' of string type'
|
|
318
|
-
)
|
|
319
|
-
}
|
|
320
|
-
})
|
|
321
|
-
it("should throw an error if 'name' property is not included", async () => {
|
|
322
|
-
try {
|
|
323
|
-
const file = {
|
|
324
|
-
size: 5000,
|
|
325
|
-
type: 'text/plain'
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
await bchjs.IPFS.uploadFileWeb(file)
|
|
329
|
-
|
|
330
|
-
assert.equal(true, false, 'Unexpected result')
|
|
331
|
-
} catch (err) {
|
|
332
|
-
// console.log(`err.message: ${err.message}`)
|
|
333
|
-
assert.include(
|
|
334
|
-
err.message,
|
|
335
|
-
'File should have the property \'name\' of string type'
|
|
336
|
-
)
|
|
337
|
-
}
|
|
338
|
-
})
|
|
339
|
-
it("should throw an error if 'size' property is not included", async () => {
|
|
340
|
-
try {
|
|
341
|
-
const file = {
|
|
342
|
-
name: 'ipfs.js',
|
|
343
|
-
type: 'text/plain'
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
await bchjs.IPFS.uploadFileWeb(file)
|
|
347
|
-
|
|
348
|
-
assert.equal(true, false, 'Unexpected result')
|
|
349
|
-
} catch (err) {
|
|
350
|
-
// console.log(`err.message: ${err.message}`)
|
|
351
|
-
assert.include(
|
|
352
|
-
err.message,
|
|
353
|
-
'File should have the property \'size\' of number type'
|
|
354
|
-
)
|
|
355
|
-
}
|
|
356
|
-
})
|
|
357
|
-
it("should throw an error if 'type' property is not included", async () => {
|
|
358
|
-
try {
|
|
359
|
-
const file = {
|
|
360
|
-
name: 'ipfs.js',
|
|
361
|
-
size: 5000
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
await bchjs.IPFS.uploadFileWeb(file)
|
|
365
|
-
|
|
366
|
-
assert.equal(true, false, 'Unexpected result')
|
|
367
|
-
} catch (err) {
|
|
368
|
-
// console.log(`err.message: ${err.message}`)
|
|
369
|
-
assert.include(
|
|
370
|
-
err.message,
|
|
371
|
-
'File should have the property \'type\' of string type'
|
|
372
|
-
)
|
|
373
|
-
}
|
|
374
|
-
})
|
|
375
|
-
it('should throw an error if modelId is not included', async () => {
|
|
376
|
-
try {
|
|
377
|
-
const file = {
|
|
378
|
-
name: 'ipfs.js',
|
|
379
|
-
size: 5000,
|
|
380
|
-
type: 'text/plain'
|
|
381
|
-
}
|
|
382
|
-
await bchjs.IPFS.uploadFileWeb(file)
|
|
383
|
-
|
|
384
|
-
assert.equal(true, false, 'Unexpected result')
|
|
385
|
-
} catch (err) {
|
|
386
|
-
// console.log(`err.message: ${err.message}`)
|
|
387
|
-
assert.include(err.message, 'Must include a file model ID')
|
|
388
|
-
}
|
|
389
|
-
})
|
|
390
|
-
|
|
391
|
-
it('Should throw error if the file was not uploaded', async () => {
|
|
392
|
-
try {
|
|
393
|
-
const mock = {
|
|
394
|
-
successful: [],
|
|
395
|
-
failed: [
|
|
396
|
-
{
|
|
397
|
-
id: 'file id'
|
|
398
|
-
}
|
|
399
|
-
]
|
|
400
|
-
}
|
|
401
|
-
sandbox.stub(bchjs.IPFS.uppy, 'upload').resolves(mock)
|
|
402
|
-
|
|
403
|
-
const file = {
|
|
404
|
-
name: 'ipfs.js',
|
|
405
|
-
size: 5000,
|
|
406
|
-
type: 'text/plain'
|
|
407
|
-
}
|
|
408
|
-
await bchjs.IPFS.uploadFileWeb(file, '5ec562319bfacc745e8d8a52')
|
|
409
|
-
|
|
410
|
-
assert.equal(true, false, 'Unexpected result')
|
|
411
|
-
} catch (err) {
|
|
412
|
-
// console.log(err)
|
|
413
|
-
assert.include(err.message, 'The file could not be uploaded')
|
|
414
|
-
}
|
|
415
|
-
})
|
|
416
|
-
|
|
417
|
-
it('should return file object if the file is uploaded', async () => {
|
|
418
|
-
try {
|
|
419
|
-
sandbox.stub(bchjs.IPFS.uppy, 'upload').resolves(mockData.uploadData)
|
|
420
|
-
|
|
421
|
-
const file = {
|
|
422
|
-
name: 'ipfs.js',
|
|
423
|
-
size: 5000,
|
|
424
|
-
type: 'text/plain'
|
|
425
|
-
}
|
|
426
|
-
const result = await bchjs.IPFS.uploadFileWeb(
|
|
427
|
-
file,
|
|
428
|
-
'5ec562319bfacc745e8d8a52'
|
|
429
|
-
)
|
|
430
|
-
// console.log(`result: ${JSON.stringify(result, null, 2)}`)
|
|
431
|
-
|
|
432
|
-
assert.property(result, 'schemaVersion')
|
|
433
|
-
assert.property(result, 'size')
|
|
434
|
-
assert.property(result, 'fileId')
|
|
435
|
-
assert.property(result, 'fileName')
|
|
436
|
-
assert.property(result, 'fileExtension')
|
|
437
|
-
} catch (err) {
|
|
438
|
-
// console.log(err)
|
|
439
|
-
assert.equal(true, false, 'Unexpected result')
|
|
440
|
-
}
|
|
441
|
-
})
|
|
442
|
-
})
|
|
443
|
-
})
|