Skip to content

Commit

Permalink
Merge pull request #32 from dimitrov-d/master
Browse files Browse the repository at this point in the history
3.1.0 - New storage methods and Project module
  • Loading branch information
MoMannn committed May 8, 2024
2 parents 60d6a0a + 2864641 commit 9baf62a
Show file tree
Hide file tree
Showing 14 changed files with 469 additions and 426 deletions.
646 changes: 270 additions & 376 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
},
"packageManager": "[email protected]",
"devDependencies": {
"@types/jest": "^29.5.12",
"eslint-config-common": "*",
"jest": "29.7.0",
"prettier": "latest",
"rimraf": "^5.0.5",
"turbo": "latest",
"jest": "29.7.0",
"ts-jest": "29.1.1",
"@types/jest": "^29.5.11"
"ts-jest": "29.1.2",
"turbo": "latest"
},
"jest": {
"testTimeout": 1800000,
Expand All @@ -53,4 +53,4 @@
"preset": "ts-jest",
"verbose": true
}
}
}
4 changes: 2 additions & 2 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,14 @@
],
"devDependencies": {
"eslint-config-common": "*",
"nodemon": "^3.0.2",
"nodemon": "^3.1.0",
"rimraf": "^5.0.5",
"ts-node": "^10.9.2",
"tsconfig": "*"
},
"dependencies": {
"@apillon/sdk": "*",
"axios": "^1.6.2",
"axios": "^1.6.8",
"chalk": "^4.1.2",
"commander": "^11.1.0"
}
Expand Down
4 changes: 4 additions & 0 deletions packages/sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@ await bucket.listObjects({
// list all files in a bucket no matter if they are in a folder or not
await bucket.listFiles({ fileStatus: FileStatus.UPLOADED });

// generate an IPFS link for a CID
const cid = 'bafybeigjhyc2tpvqfqsuvf3byo4e4a4v6spi6jk4qqvvtlpca6rsaf2cqi';
const link = await storage.generateIpfsLink(cid);

// gets a specific file in a bucket directly through uuid
const file = await bucket.file('2195521d-15cc-4f6e-abf2-13866f9c6e03').get();

Expand Down
14 changes: 7 additions & 7 deletions packages/sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@apillon/sdk",
"description": "▶◀ Apillon SDK for NodeJS ▶◀",
"version": "3.0.0",
"version": "3.1.0",
"author": "Apillon",
"license": "MIT",
"main": "./dist/index.js",
Expand Down Expand Up @@ -45,20 +45,20 @@
],
"dependencies": {
"@polkadot/util-crypto": "^12.6.2",
"axios": "^1.6.2",
"axios": "^1.6.8",
"ethereumjs-util": "^7.1.5"
},
"devDependencies": {
"@polkadot/keyring": "^12.6.2",
"@types/jest": "^29.5.11",
"dotenv": "^16.3.1",
"@types/jest": "^29.5.12",
"dotenv": "^16.4.5",
"eslint-config-common": "*",
"ethers": "^6.9.0",
"nodemon": "^3.0.2",
"ethers": "^6.12.0",
"nodemon": "^3.1.0",
"rimraf": "^5.0.5",
"ts-node": "^10.9.2",
"tsconfig": "*",
"typedoc": "^0.25.4"
"typedoc": "^0.25.13"
},
"jest": {
"testTimeout": 1800000,
Expand Down
1 change: 1 addition & 0 deletions packages/sdk/src/docs-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ export * from './modules/computing/computing-contract';
export * from './modules/social/social';
export * from './modules/social/social-hub';
export * from './modules/social/social-channel';
export * from './modules/project/project';
1 change: 1 addition & 0 deletions packages/sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export * from './modules/nft/nft';
export * from './modules/identity/identity';
export * from './modules/computing/computing';
export * from './modules/social/social';
export * from './modules/project/project';
20 changes: 20 additions & 0 deletions packages/sdk/src/modules/project/project.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { ApillonModule } from '../../lib/apillon';
import { ApillonApi } from '../../lib/apillon-api';

export class Project extends ApillonModule {
/**
* Base API url for project.
*/
private API_PREFIX = '/project';

/**
* Get credit balance for your project
* @returns {Promise<number>} The credit balance of your project
*/
public async getCreditBalance(): Promise<number> {
const { balance } = await ApillonApi.get<{ balance: number }>(
`${this.API_PREFIX}/credit`,
);
return balance;
}
}
16 changes: 6 additions & 10 deletions packages/sdk/src/modules/storage/storage-bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,7 @@ export class StorageBucket extends ApillonModel {
* @returns List of files in the bucket
*/
async listFiles(params?: IBucketFilesRequest): Promise<IApillonList<File>> {
const url = constructUrlWithQueryParams(
`/storage/buckets/${this.uuid}/files`,
params,
);
const url = constructUrlWithQueryParams(`${this.API_PREFIX}/files`, params);
const data = await ApillonApi.get<
IApillonList<File & { fileUuid: string }>
>(url);
Expand Down Expand Up @@ -227,10 +224,7 @@ export class StorageBucket extends ApillonModel {
* @returns List of IPNS names in the bucket
*/
async listIpnsNames(params?: IPNSListRequest) {
const url = constructUrlWithQueryParams(
`/storage/buckets/${this.uuid}/ipns`,
params,
);
const url = constructUrlWithQueryParams(`${this.API_PREFIX}/ipns`, params);
const data = await ApillonApi.get<
IApillonList<Ipns & { ipnsUuid: string }>
>(url);
Expand All @@ -247,8 +241,10 @@ export class StorageBucket extends ApillonModel {
* @returns New IPNS instance
*/
async createIpns(body: ICreateIpns): Promise<Ipns> {
const url = `/storage/buckets/${this.uuid}/ipns`;
const data = await ApillonApi.post<Ipns & { ipnsUuid: string }>(url, body);
const data = await ApillonApi.post<Ipns & { ipnsUuid: string }>(
`${this.API_PREFIX}/ipns`,
body,
);
return new Ipns(this.uuid, data.ipnsUuid, data);
}
//#endregion
Expand Down
44 changes: 42 additions & 2 deletions packages/sdk/src/modules/storage/storage.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { IpfsClusterInfo, StorageInfo } from '../../docs-index';
import { ApillonModule } from '../../lib/apillon';
import { ApillonApi } from '../../lib/apillon-api';
import { constructUrlWithQueryParams } from '../../lib/common';
Expand All @@ -8,7 +9,7 @@ export class Storage extends ApillonModule {
/**
* API url for storage.
*/
private API_PREFIX = '/storage/buckets';
private API_PREFIX = '/storage';

/**
* Lists all buckets.
Expand All @@ -18,7 +19,10 @@ export class Storage extends ApillonModule {
public async listBuckets(
params?: IApillonPagination,
): Promise<IApillonList<StorageBucket>> {
const url = constructUrlWithQueryParams(this.API_PREFIX, params);
const url = constructUrlWithQueryParams(
`${this.API_PREFIX}/buckets`,
params,
);

const data = await ApillonApi.get<
IApillonList<StorageBucket & { bucketUuid: string }>
Expand All @@ -39,4 +43,40 @@ export class Storage extends ApillonModule {
public bucket(uuid: string): StorageBucket {
return new StorageBucket(uuid);
}

/**
* Gets overall storage info for a project - available and used storage and bandwidth
* @returns {Promise<StorageInfo>}
*/
public async getInfo(): Promise<StorageInfo> {
return await ApillonApi.get<StorageInfo>(`${this.API_PREFIX}/info`);
}

/**
* Gets basic data of an IPFS cluster used by the project.
*
* IPFS clusters contain multiple IPFS nodes but expose a single gateway for accessing content via CID or IPNS.
*
* Apillon clusters (gateways) are not publicly accessible
* @note Each project has its own secret for generating tokens to access content on the IPFS gateway.
* @returns {Promise<IpfsClusterInfo>}
*/
public async getIpfsClusterInfo(): Promise<IpfsClusterInfo> {
return await ApillonApi.get<IpfsClusterInfo>(
`${this.API_PREFIX}/ipfs-cluster-info`,
);
}

/**
* Apillon IPFS gateways are private and can only be accessible with a token.
* @docs [Generate an IPFS link](https://wiki.apillon.io/build/2-storage-api.html#get-or-generate-link-for-ipfs)
* @param {string} cid The CID or IPNS address of the fie
* @returns {Promise<string>} The IPFS link where the requested content can be accessed.
*/
public async generateIpfsLink(cid: string): Promise<string> {
const { link } = await ApillonApi.get<{ link: string }>(
`${this.API_PREFIX}/link-on-ipfs/${cid}`,
);
return link;
}
}
16 changes: 8 additions & 8 deletions packages/sdk/src/tests/nft.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,11 @@ describe('Nft tests', () => {
receivingAddress = getMintAddress();
});

test('list nft collections', async () => {
const { items: collections } = await nft.listCollections();
expect(collections.length).toBeGreaterThan(0);
expect(collections[0]).toBeInstanceOf(NftCollection);
});

test('creates a new collection', async () => {
const collection = await nft.create({
...nftData,
chain: EvmChain.MOONBASE,
isRevokable: true,
isRevokable: false,
isSoulbound: true,
});
expect(collection.uuid).toBeDefined();
Expand All @@ -45,12 +39,18 @@ describe('Nft tests', () => {
expect(collection.name).toEqual('SDK Test');
expect(collection.description).toEqual('Created from SDK tests');
expect(collection.isAutoIncrement).toEqual(true);
expect(collection.isRevokable).toEqual(true);
expect(collection.isRevokable).toEqual(false);
expect(collection.isSoulbound).toEqual(true);

collectionUuid = collection.uuid;
});

test('list nft collections', async () => {
const { items: collections } = await nft.listCollections();
expect(collections.length).toBeGreaterThan(0);
expect(collections[0]).toBeInstanceOf(NftCollection);
});

test('creates a new substrate collection', async () => {
const collection = await nft.createSubstrate({
...nftData,
Expand Down
17 changes: 17 additions & 0 deletions packages/sdk/src/tests/project.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { getConfig } from './helpers/helper';
import { Project } from '../modules/project/project';

describe('Project Module tests', () => {
let project: Project;

beforeAll(async () => {
project = new Project(getConfig());
});

describe('Project module tests', () => {
test('Get project credit balance', async () => {
const balance = await project.getCreditBalance();
expect(balance).toBeGreaterThan(0);
});
});
});
63 changes: 47 additions & 16 deletions packages/sdk/src/tests/storage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,6 @@ describe('Storage tests', () => {
items.forEach((item) => expect(item.name).toBeTruthy());
});

test('get file details', async () => {
const file = await storage.bucket(bucketUuid).file(fileUuid).get();
expect(file.name).toBeTruthy();
});

test('upload files from folder', async () => {
const uploadDir = resolve(__dirname, './helpers/website/');

Expand All @@ -109,13 +104,13 @@ describe('Storage tests', () => {
test('upload files from folder with ignoreFiles = false', async () => {
const uploadDir = resolve(__dirname, './helpers/website/');

console.time('File upload complete');
const files = await storage
.bucket(bucketUuid)
.uploadFromFolder(uploadDir, { ignoreFiles: false });
expect(files.length).toEqual(3); // .gitignore and index.html are not ignored

console.timeEnd('File upload complete');
// .gitignore and index.html are not ignored
// and HTML files are not allowed
await expect(
storage
.bucket(bucketUuid)
.uploadFromFolder(uploadDir, { ignoreFiles: false }),
).rejects.toThrow();
});

test('upload files from buffer', async () => {
Expand All @@ -140,11 +135,47 @@ describe('Storage tests', () => {
console.timeEnd('File upload complete');
});

test.skip('delete a file', async () => {
await storage.bucket(bucketUuid).file(fileUuid).delete();
describe.skip('File detail tests', () => {
test('get file details', async () => {
const file = await storage.bucket(bucketUuid).file(fileUuid).get();
expect(file.name).toBeTruthy();
});

test('delete a file', async () => {
await storage.bucket(bucketUuid).file(fileUuid).delete();
});

test('delete a directory', async () => {
await storage.bucket(bucketUuid).directory(directoryUuid).delete();
});
});

test.skip('delete a directory', async () => {
await storage.bucket(bucketUuid).directory(directoryUuid).delete();
describe('Storage info tests', () => {
test('Get storage info', async () => {
const info = await storage.getInfo();
expect(info).toBeDefined();
expect(info.availableStorage).toBeGreaterThan(0);
expect(info.usedStorage).toBeGreaterThanOrEqual(0);
expect(info.usedStorage).toBeLessThan(info.availableStorage);
expect(info.availableBandwidth).toBeGreaterThan(0);
expect(info.usedBandwidth).toBeGreaterThanOrEqual(0);
expect(info.usedBandwidth).toBeLessThan(info.availableBandwidth);
});

test('Get IPFS cluster info', async () => {
const ipfsClusterInfo = await storage.getIpfsClusterInfo();
expect(ipfsClusterInfo).toBeDefined();
expect(ipfsClusterInfo.secret).toBeDefined();
expect(ipfsClusterInfo.projectUuid).toBeDefined();
expect(ipfsClusterInfo.ipfsGateway).toBeDefined();
expect(ipfsClusterInfo.ipnsGateway).toBeDefined();
});

test('Generate IPFS link', async () => {
const cid = 'bafybeigjhyc2tpvqfqsuvf3byo4e4a4v6spi6jk4qqvvtlpca6rsaf2cqi';
const link = await storage.generateIpfsLink(cid);
expect(link).toBeDefined();
expect(link).toContain(cid);
});
});
});
Loading

0 comments on commit 9baf62a

Please sign in to comment.