@@ -32,139 +32,53 @@ Since we use `@graphprotocol/graph-ts` we must submit items to its ipfs endpoint
32
32
Full example [ here] ( https://github.com/kleros/gtcr/blob/5e313ced24f5e3fc3a54f812e07fb1f86a6b2621/src/utils/ipfs-publish.js )
33
33
34
34
``` text
35
- REACT_APP_IPFS_GATEWAY=https://ipfs .kleros.io
35
+ REACT_APP_IPFS_GATEWAY=https://cdn .kleros.link
36
36
REACT_APP_HOSTED_GRAPH_IPFS_ENDPOINT=https://api.thegraph.com/ipfs
37
37
```
38
38
39
39
#### Upload and Transaction
40
40
41
- ``` text
42
- // ipfs-publish.js
43
-
44
- import deepEqual from 'fast-deep-equal/es6'
45
-
46
- const mirroredExtensions = ['.json']
47
-
48
- /**
49
- * Send file to IPFS network.
50
- * @param {string} fileName - The name that will be used to store the file. This is useful to preserve extension type.
51
- * @param {ArrayBuffer} data - The raw data from the file to upload.
52
- * @returns {object} ipfs response. Should include the hash and path of the stored item.
53
- */
54
- export default async function ipfsPublish(fileName, data) {
55
- if (!mirroredExtensions.some(ext => fileName.endsWith(ext)))
56
- return publishToKlerosNode(fileName, data)
57
-
58
- const [klerosResult, theGraphResult] = await Promise.all([
59
- publishToKlerosNode(fileName, data),
60
- publishToTheGraphNode(fileName, data),
61
- // Pin to your own ipfs node here as well.
62
- ])
63
-
64
- if (!deepEqual(klerosResult, theGraphResult)) {
65
- console.warn('IPFS upload result is different:', {
66
- kleros: klerosResult,
67
- theGraph: theGraphResult
68
- })
69
- throw new Error('IPFS upload result is different.')
70
- }
71
-
72
- return klerosResult
73
- }
41
+ ``` typescript
42
+ const pinFiles = async (
43
+ data : FormData ,
44
+ pinToGraph : boolean
45
+ ): Promise <
46
+ [Array < string > , Array < { filebaseCid: string ; graphCid : string }> ]
47
+ > => {
48
+ const cids = new Array <string >();
49
+ // keep track in case some cids are inconsistent
50
+ const inconsistentCids = new Array <{
51
+ filebaseCid: string ;
52
+ graphCid: string ;
53
+ }>();
54
+
55
+ for (const [_, dataElement] of Object .entries (data )) {
56
+ if (dataElement .isFile ) {
57
+ const { filename, mimeType, content } = dataElement ;
58
+ const path = ` ${filename } ` ;
59
+ const cid = await filebase .storeDirectory ([
60
+ new File ([content ], path , { type: mimeType }),
61
+ ]);
62
+
63
+ if (pinToGraph ) {
64
+ const graphResult = await publishToGraph (filename , content );
65
+ if (! areCidsConsistent (cid , graphResult )) {
66
+ console .warn (" Inconsistent cids from Filebase and Graph Node :" , {
67
+ filebaseCid: cid ,
68
+ graphCid: graphResult [1 ].hash ,
69
+ });
70
+ inconsistentCids .push ({
71
+ filebaseCid: cid ,
72
+ graphCid: graphResult [1 ].hash ,
73
+ });
74
+ }
75
+ }
74
76
75
- /**
76
- * Send file to IPFS network via the Kleros IPFS node
77
- * @param {string} fileName - The name that will be used to store the file. This is useful to preserve extension type.
78
- * @param {ArrayBuffer} data - The raw data from the file to upload.
79
- * @returns {object} ipfs response. Should include the hash and path of the stored item.
80
- */
81
- async function publishToKlerosNode(fileName, data) {
82
- const buffer = await Buffer.from(data)
83
- const url = `${process.env.REACT_APP_IPFS_GATEWAY}/add`
84
-
85
- const response = await fetch(url, {
86
- method: 'POST',
87
- body: JSON.stringify({
88
- fileName,
89
- buffer
90
- }),
91
- headers: {
92
- 'content-type': 'application/json'
77
+ cids .push (` /ipfs/${cid }/${path } ` );
93
78
}
94
- })
95
-
96
- const body = await response.json()
97
-
98
- return body.data
99
- }
100
-
101
- /**
102
- * Send file to IPFS network via The Graph hosted IPFS node
103
- * @param {string} fileName - The name that will be used to store the file. This is useful to preserve extension type.
104
- * @param {ArrayBuffer} data - The raw data from the file to upload.
105
- * @returns {object} ipfs response. Should include the hash and path of the stored item.
106
- */
107
- async function publishToTheGraphNode(fileName, data) {
108
- const url = `${process.env.REACT_APP_HOSTED_GRAPH_IPFS_ENDPOINT}/api/v0/add?wrap-with-directory=true`
109
-
110
- const payload = new FormData()
111
- payload.append('file', new Blob([data]), fileName)
112
-
113
- const response = await fetch(url, {
114
- method: 'POST',
115
- body: payload
116
- })
117
-
118
- const result = await jsonStreamToPromise(response.body)
119
-
120
- return result.map(({ Name, Hash }) => ({
121
- hash: Hash,
122
- path: `/${Name}`
123
- }))
124
- }
125
-
126
- /**
127
- * Accumulates a JSON stream body into an array of JSON objects.
128
- * @param {ReadableStream} stream The stream to read from.
129
- * @returns {Promise<any>} An array of all JSON objects emitted by the stream.
130
- */
131
- async function jsonStreamToPromise(stream) {
132
- const reader = stream.getReader()
133
- const decoder = new TextDecoder('utf-8')
134
-
135
- const deferred = {
136
- resolve: undefined,
137
- reject: undefined
138
- }
139
-
140
- const result = new Promise((resolve, reject) => {
141
- deferred.resolve = resolve
142
- deferred.reject = reject
143
- })
144
-
145
- const acc = []
146
- const start = async () => {
147
- reader
148
- .read()
149
- .then(({ done, value }) => {
150
- if (done) return deferred.resolve(acc)
151
-
152
- // Each `read` can produce one or more lines...
153
- const lines = decoder.decode(value).split(/\n/)
154
- const objects = lines
155
- .filter(line => line.trim() !== '')
156
- .map(line => JSON.parse(line))
157
- acc.push(...objects)
158
-
159
- return start()
160
- })
161
- .catch(err => deferred.reject(err))
162
79
}
163
-
164
- start()
165
-
166
- return result
167
- }
80
+ return [cids , inconsistentCids ];
81
+ };
168
82
```
169
83
170
84
The JSON file for the object is composed of the its metadata and fields.
@@ -258,7 +172,7 @@ See [this react example](https://github.com/kleros/gtcr/blob/5e313ced24f5e3fc3a5
258
172
259
173
A standard query for the first page of a given list, ordered by the most recent requests, looks like this.
260
174
261
- ``` javascript
175
+ ``` typescript
262
176
const ITEMS_PER_PAGE = 40
263
177
const orderDirection = ' asc'
264
178
const page = 1
@@ -314,7 +228,7 @@ const query = {
314
228
315
229
If you want, you can also use apollo to cache queries and make the app load faster.
316
230
317
- ``` text
231
+ ``` typescript
318
232
const ITEM_DETAILS_QUERY = gql `
319
233
query itemDetailsQuery($id: String!) {
320
234
item(id: $id) {
0 commit comments