Skip to content

Commit 73ba850

Browse files
authored
enable alternative gateway for image upload (#136)
1 parent 348512b commit 73ba850

File tree

5 files changed

+49
-13
lines changed

5 files changed

+49
-13
lines changed

.changeset/lucky-trains-scream.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@graphprotocol/grc-20": patch
3+
---
4+
5+
automatically upload images to the alternative ipfs gateway

src/graph/constants.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export const MAINNET_API_ORIGIN = 'https://hypergraph-v2.up.railway.app';
2-
export const TESTNET_API_ORIGIN = 'https://api-testnet.geobrowser.io';
2+
export const TESTNET_API_ORIGIN = 'https://api-testnet.geobrowser.io';

src/graph/create-image.test.ts

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
import { beforeEach, describe, expect, it, vi } from 'vitest';
22
import { Id } from '../id.js';
33
import { SystemIds } from '../system-ids.js';
4-
import { MAINNET_API_ORIGIN } from './constants.js';
4+
import { MAINNET_API_ORIGIN, TESTNET_API_ORIGIN } from './constants.js';
55
import { createImage } from './create-image.js';
66

77
// serialized like this:
88
// const buffer = Buffer.from(await blob.arrayBuffer());
99
// const base64 = buffer.toString('base64');
1010
// console.log('base64', base64);
1111
const testImageContent =
12-
'iVBORw0KGgoAAAANSUhEUgAAAAoAAAAHCAMAAAAGcixRAAAAY1BMVEXvvubYz97i2Ojm3Oz4vu3gv+f2yfTqxvDj1v/hxe/u0Pvn1v3Oxc7wx/LHs87r2uzYs7np3++lnaPq1OrZxtjx3PL8xPLG0OXjyuHizeS3qsDfz+nMu8PZtc3TvNjdyO77z/t7oOngAAAACnRSTlP+////y/7e/tbEPoYQ1AAAAAlwSFlzAAALEwAACxMBAJqcGAAAAEhJREFUeNoFwQkCQDAMBMBNgtJL77r5/yvNYPqc1toYM+Pt1VPcgjDGvj4ke2BGS3Y9SSQRUDh7kkKM+5J82OptxNAA55TSyw+IpgNhAhO+gAAAAABJRU5ErkJggg==';
12+
'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';
1313

1414
const testImageBlob = new Blob([Buffer.from(testImageContent, 'base64')], { type: 'image/png' });
1515
const ipfsUploadUrl = `${MAINNET_API_ORIGIN}/ipfs/upload-file`;
@@ -30,6 +30,12 @@ describe('createImage', () => {
3030
json: () => Promise.resolve({ cid: 'ipfs://bafkreidgcqofpstvkzylgxbcn4xan6camlgf564sasepyt45sjgvnojxp4' }),
3131
} as Response);
3232
}
33+
if (url.toString() === `${TESTNET_API_ORIGIN}/ipfs/upload-file-alternative-gateway`) {
34+
return Promise.resolve({
35+
status: 200,
36+
json: () => Promise.resolve({ cid: 'ipfs://bafkreidgcqofpstvkzylgxbcn4xan6camlgf564sasepyt45sjgvnojxp4' }),
37+
} as Response);
38+
}
3339
return vi.fn() as never;
3440
});
3541
});
@@ -43,8 +49,8 @@ describe('createImage', () => {
4349
expect(typeof image.id).toBe('string');
4450
expect(image.cid).toBe('ipfs://bafkreidgcqofpstvkzylgxbcn4xan6camlgf564sasepyt45sjgvnojxp4');
4551
expect(image.dimensions).toBeDefined();
46-
expect(image.dimensions?.width).toBe(10);
47-
expect(image.dimensions?.height).toBe(7);
52+
expect(image.dimensions?.width).toBe(16);
53+
expect(image.dimensions?.height).toBe(6);
4854
expect(image.ops).toBeDefined();
4955
expect(image.ops).toHaveLength(2);
5056
if (image.ops[0]) {
@@ -61,6 +67,24 @@ describe('createImage', () => {
6167
}
6268
});
6369

70+
it('creates an image on TESTNET from a blob', async () => {
71+
const image = await createImage({
72+
blob: testImageBlob,
73+
network: 'TESTNET',
74+
});
75+
76+
expect(image.cid).toMatch(/^ipfs:\/\/ba/);
77+
expect(image.dimensions).toBeDefined();
78+
expect(image.ops).toBeDefined();
79+
expect(image.ops).toHaveLength(2);
80+
if (image.ops[0]) {
81+
expect(image.ops[0].type).toBe('UPDATE_ENTITY');
82+
}
83+
if (image.ops[1]) {
84+
expect(image.ops[1].type).toBe('CREATE_RELATION');
85+
}
86+
});
87+
6488
it('creates an image from a blob', async () => {
6589
const image = await createImage({
6690
blob: testImageBlob,
@@ -70,8 +94,8 @@ describe('createImage', () => {
7094
expect(typeof image.id).toBe('string');
7195
expect(image.cid).toBe('ipfs://bafkreidgcqofpstvkzylgxbcn4xan6camlgf564sasepyt45sjgvnojxp4');
7296
expect(image.dimensions).toBeDefined();
73-
expect(image.dimensions?.width).toBe(10);
74-
expect(image.dimensions?.height).toBe(7);
97+
expect(image.dimensions?.width).toBe(16);
98+
expect(image.dimensions?.height).toBe(6);
7599
expect(image.ops).toBeDefined();
76100
expect(image.ops).toHaveLength(2);
77101
if (image.ops[0]) {

src/graph/create-image.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export const createImage = async ({
4646
if (providedId) assertValid(providedId, '`id` in `createImage`');
4747

4848
const id = providedId ?? generate();
49-
const { cid, dimensions } = await uploadImage(params, network);
49+
const { cid, dimensions } = await uploadImage(params, network, network === 'TESTNET');
5050

5151
const values: PropertiesParam = [];
5252
values.push({

src/ipfs.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ type PublishImageParams =
7474
url: string;
7575
};
7676

77-
export async function uploadImage(params: PublishImageParams, network?: 'TESTNET' | 'MAINNET') {
77+
export async function uploadImage(params: PublishImageParams, network?: 'TESTNET' | 'MAINNET', alternativeGateway?: boolean) {
7878
const formData = new FormData();
7979
let blob: Blob;
8080
if ('blob' in params) {
@@ -93,7 +93,7 @@ export async function uploadImage(params: PublishImageParams, network?: 'TESTNET
9393
dimensions = imageSize(buffer);
9494
} catch (_error) {}
9595

96-
const cid = await Micro.runPromise(uploadFile(formData, network));
96+
const cid = await Micro.runPromise(uploadFile(formData, network, alternativeGateway));
9797

9898
if (dimensions) {
9999
return {
@@ -188,15 +188,22 @@ function uploadBinary(formData: FormData, network?: 'TESTNET' | 'MAINNET') {
188188
});
189189
}
190190

191-
function uploadFile(formData: FormData, network?: 'TESTNET' | 'MAINNET') {
191+
function uploadFile(formData: FormData, network?: 'TESTNET' | 'MAINNET', alternativeGateway?: boolean) {
192192
return Micro.gen(function* () {
193+
let apiUrl = `${network === 'TESTNET' ? TESTNET_API_ORIGIN : MAINNET_API_ORIGIN}/ipfs/upload-file`;
194+
if (alternativeGateway) {
195+
apiUrl = `${TESTNET_API_ORIGIN}/ipfs/upload-file-alternative-gateway`;
196+
}
197+
193198
const result = yield* Micro.tryPromise({
194199
try: () =>
195-
fetch(`${network === 'TESTNET' ? TESTNET_API_ORIGIN : MAINNET_API_ORIGIN}/ipfs/upload-file`, {
200+
fetch(apiUrl, {
196201
method: 'POST',
197202
body: formData,
198203
}),
199-
catch: error => new IpfsUploadError(`Could not upload file to IPFS: ${error}`),
204+
catch: error => {
205+
return new IpfsUploadError(`Could not upload file to IPFS: ${error}`)
206+
},
200207
});
201208

202209
const maybeCid = yield* Micro.tryPromise({

0 commit comments

Comments
 (0)