Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
node_modules
pnpm-lock.yaml
node_modules
lib
12 changes: 7 additions & 5 deletions src/APIManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@ import { APIResponse, RawUserData } from './typings';
import axios, { AxiosRequestConfig } from 'axios';

export class SquareCloudAPIError extends Error {
constructor(code: string) {
constructor(code: string, message?: string) {
super();

this.name = 'SquareCloudAPIError';

this.message = code
.replaceAll('_', ' ')
.toLowerCase()
.replace(/(^|\s)\S/g, (L) => L.toUpperCase());
this.message =
code
.replaceAll('_', ' ')
.toLowerCase()
.replace(/(^|\s)\S/g, (L) => L.toUpperCase()) +
(message ? `: ${message}` : '');
}
}

Expand Down
60 changes: 48 additions & 12 deletions src/Assertions.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,58 @@
import { SquareCloudAPIError } from './APIManager';
import { ReadStream } from 'fs';
import z from 'zod';

export function validateString(value: any): asserts value is string {
z.string().parse(value);
export function validateString(
value: any,
code?: string,
starts: string = ''
): asserts value is string {
if (starts) validateString(starts);

handleParser(
() => z.string().parse(value),
'Expect string, got ' + typeof value,
code
);
}

export function validateBoolean(value: any): asserts value is boolean {
z.boolean().parse(value);
export function validateBoolean(
value: any,
code?: string
): asserts value is boolean {
handleParser(
() => z.boolean().parse(value),
'Expect boolean, got ' + typeof value,
code
);
}

export function validateCommitLike(
value: any
): asserts value is string | ReadStream {
z.string()
.or(
value: any,
code?: string
): asserts value is string | ReadStream | Buffer {
handleParser(
() =>
z
.custom((value) => value instanceof ReadStream)
.or(z.custom((value) => value instanceof Buffer))
)
.parse(value);
.string()
.or(
z
.custom((value) => value instanceof ReadStream)
.or(z.custom((value) => value instanceof Buffer))
)
.parse(value),
'Expect string, ReadStream or Buffer, got ' + typeof value,
code
);
}

function handleParser(func: any, message: string, code?: string) {
try {
func();
} catch {
throw new SquareCloudAPIError(
code ? `INVALID_${code}` : 'VALIDATION_ERROR',
message
);
}
}
8 changes: 4 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ export class SquareCloudAPI {
baseUrl: 'https://api.squarecloud.app/v1/public/',
};

private apiManager: APIManager;
public readonly apiManager: APIManager;

/**
* Creates an API instance
*
* @param apiKey - Your API Token (you can get it at [SquareCloud Dashboard](https://squarecloud.app/dashboard))
*/
constructor(apiKey: string) {
validateString(apiKey);
validateString(apiKey, 'API_KEY');

this.apiManager = new APIManager(apiKey);
}
Expand All @@ -30,7 +30,7 @@ export class SquareCloudAPI {
async getUser(): Promise<FullUser>;
async getUser(userId: string): Promise<User>;
async getUser(userId?: string): Promise<User> {
if (userId) validateString(userId);
if (userId) validateString(userId, 'USER_ID');

const userData = await this.apiManager.user(userId);
const hasAccess = userData.user.email !== 'Access denied';
Expand All @@ -44,7 +44,7 @@ export class SquareCloudAPI {
* @param appId - The application id, you must own the application
*/
async getApplication(appId: string): Promise<Application> {
validateString(appId);
validateString(appId, 'APP_ID');

const { applications } = await this.apiManager.user();
const appData = applications.find((app) => app.id === appId);
Expand Down
44 changes: 33 additions & 11 deletions src/structures/Application.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { RawApplicationData, ApplicationStatusData } from '../typings';
import { validateBoolean, validateCommitLike } from '../Assertions';
import {
validateBoolean,
validateCommitLike,
validateString,
} from '../Assertions';
import { createReadStream, ReadStream } from 'fs';
import { APIManager } from '../APIManager';
import FormData from 'form-data';
Expand Down Expand Up @@ -81,7 +85,7 @@ export class Application {
* @param full - Whether you want the complete logs (true) or the recent ones (false)
*/
async getLogs(full: boolean = false) {
validateBoolean(full);
validateBoolean(full, '[LOGS_FULL]');

return (
await this.apiManager.application(`${full ? 'full-' : ''}logs`, this.id)
Expand Down Expand Up @@ -134,22 +138,40 @@ export class Application {
* Commit changes to a specific file inside your application folder
*
* - This action is irreversible.
* - Tip: use `require('path').join(__dirname, 'fileName')` to get an absolute path.
* - Tip: use this to get an absolute path.
* ```ts
* require('path').join(__dirname, 'fileName')
* ```
* - Tip2: use zip file to commit more than one file
*
* @param file - The absolute file path or a ReadStream
*/
// async commit(file: string | ReadStream): Promise<boolean>
// async commit(file: Buffer, fileName: string, fileExtension: string): Promise<boolean>
async commit(file: string | ReadStream | Buffer, fileName?: string, fileExtension?: string): Promise<boolean> {
validateCommitLike(file);
async commit(file: string | ReadStream): Promise<boolean>;
async commit(
file: Buffer,
fileName: string,
fileExtension: `.${string}`
): Promise<boolean>;
async commit(
file: string | ReadStream | Buffer,
fileName?: string,
fileExtension?: `.${string}`
): Promise<boolean> {
validateCommitLike(file, 'COMMIT_DATA');

const formData = new FormData();

formData.append(
'file',
file instanceof ReadStream ? file : createReadStream(file)
);
if (file instanceof Buffer) {
validateString(fileName, 'FILE_NAME');
validateString(fileExtension, 'FILE_EXTENSION');

formData.append('file', file, { filename: fileName + fileExtension });
} else {
formData.append(
'file',
file instanceof ReadStream ? file : createReadStream(file)
);
}

const { code } = await this.apiManager.application('commit', this.id, {
method: 'POST',
Expand Down
Loading