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
7 changes: 4 additions & 3 deletions packages/cubejs-backend-cloud/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@
"license": "Apache-2.0",
"devDependencies": {
"@cubejs-backend/linter": "^1.0.0",
"@babel/core": "^7.24.5",
"@babel/preset-env": "^7.24.5",
"@types/fs-extra": "^9.0.8",
"@types/jest": "^27",
"@types/request-promise": "^4.1.46",
"jest": "^27",
"typescript": "~5.2.2"
},
Expand All @@ -35,10 +36,10 @@
"@cubejs-backend/shared": "1.1.10",
"chokidar": "^3.5.1",
"env-var": "^6.3.0",
"form-data": "^4.0.0",
"fs-extra": "^9.1.0",
"jsonwebtoken": "^9.0.2",
"request": "^2.88.2",
"request-promise": "^4.2.5"
"node-fetch": "^2.7.0"
},
"publishConfig": {
"access": "public"
Expand Down
134 changes: 79 additions & 55 deletions packages/cubejs-backend-cloud/src/cloud.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import rp, { RequestPromiseOptions } from 'request-promise';
import fetch, { RequestInit } from 'node-fetch';
import FormData from 'form-data';
import path from 'path';
import { ReadStream } from 'fs';

Expand All @@ -8,32 +9,49 @@ export type AuthObject = {
deploymentId?: string
};

export interface StartUploadResponse {
transaction: string;
deploymentName: string;
}

export interface UpstreamHashesResponse {
[key: string]: {
hash: string;
};
}

export class CubeCloudClient {
public constructor(
protected readonly auth?: AuthObject,
protected readonly livePreview?: boolean
) {
}

private async request(options: {
private async request<T>(options: {
url: (deploymentId: string) => string,
auth?: AuthObject,
} & RequestPromiseOptions) {
} & RequestInit): Promise<T> {
const { url, auth, ...restOptions } = options;

const authorization = auth || this.auth;
if (!authorization) {
throw new Error('Auth isn\'t set');
}
// Ensure headers object exists in restOptions
restOptions.headers = restOptions.headers || {};
// Add authorization to headers
(restOptions.headers as any).authorization = authorization.auth;

const response = await fetch(
`${authorization.url}/${url(authorization.deploymentId || '')}`,
restOptions,
);

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

return rp({
headers: {
authorization: authorization.auth
},
...restOptions,
url: `${authorization.url}/${url(authorization.deploymentId || '')}`,
json: true
});
return await response.json() as Promise<T>;
}

public getDeploymentsList({ auth }: { auth?: AuthObject } = {}) {
Expand All @@ -45,99 +63,105 @@ export class CubeCloudClient {
}

public async getDeploymentToken(authToken: string) {
const res = await rp({
url: `${process.env.CUBE_CLOUD_HOST || 'https://cubecloud.dev'}/v1/token`,
method: 'POST',
headers: {
'Content-type': 'application/json'
},
json: true,
body: {
token: authToken
const response = await fetch(
`${process.env.CUBE_CLOUD_HOST || 'https://cubecloud.dev'}/v1/token`,
{
method: 'POST',
headers: { 'Content-type': 'application/json' },
body: JSON.stringify({ token: authToken })
}
});
);

if (res && res.error) {
throw res.error;
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}

const res = await response.json() as any;

if (!res.jwt) {
throw new Error('JWT token is not present in the response');
}

return res.jwt;
}

private extendRequestByLivePreview() {
return this.livePreview ? { qs: { live: 'true' } } : {};
return this.livePreview ? '?live=true' : '';
}

public getUpstreamHashes({ auth }: { auth?: AuthObject } = {}) {
public getUpstreamHashes({ auth }: { auth?: AuthObject } = {}): Promise<UpstreamHashesResponse> {
return this.request({
url: (deploymentId: string) => `build/deploy/${deploymentId}/files`,
url: (deploymentId: string) => `build/deploy/${deploymentId}/files${this.extendRequestByLivePreview()}`,
method: 'GET',
auth,
...this.extendRequestByLivePreview()
});
}

public startUpload({ auth }: { auth?: AuthObject } = {}) {
public startUpload({ auth }: { auth?: AuthObject } = {}): Promise<StartUploadResponse> {
return this.request({
url: (deploymentId: string) => `build/deploy/${deploymentId}/start-upload`,
url: (deploymentId: string) => `build/deploy/${deploymentId}/start-upload${this.extendRequestByLivePreview()}`,
method: 'POST',
auth,
...this.extendRequestByLivePreview()
});
}

public uploadFile(
{ transaction, fileName, data, auth }:
{ transaction: any, fileName: string, data: ReadStream, auth?: AuthObject }
) {
const formData = new FormData();
formData.append('transaction', JSON.stringify(transaction));
formData.append('fileName', fileName);
formData.append('file', {
value: data,
options: {
filename: path.basename(fileName),
contentType: 'application/octet-stream'
}
});

// Get the form data buffer and headers
const formDataBuffer = formData.getBuffer();
const formDataHeaders = formData.getHeaders();

return this.request({
url: (deploymentId: string) => `build/deploy/${deploymentId}/upload-file`,
url: (deploymentId: string) => `build/deploy/${deploymentId}/upload-file${this.extendRequestByLivePreview()}`,
method: 'POST',
formData: {
transaction: JSON.stringify(transaction),
fileName,
file: {
value: data,
options: {
filename: path.basename(fileName),
contentType: 'application/octet-stream'
}
}
body: formDataBuffer,
headers: {
...formDataHeaders,
},
auth,
...this.extendRequestByLivePreview()
});
}

public finishUpload({ transaction, files, auth }:
{ transaction: any, files: any, auth?: AuthObject }) {
return this.request({
url: (deploymentId: string) => `build/deploy/${deploymentId}/finish-upload`,
url: (deploymentId: string) => `build/deploy/${deploymentId}/finish-upload${this.extendRequestByLivePreview()}`,
method: 'POST',
body: {
transaction,
files
},
body: JSON.stringify({ transaction, files }),
auth,
...this.extendRequestByLivePreview()
});
}

public setEnvVars({ envVariables, auth }: { envVariables: any, auth?: AuthObject }) {
return this.request({
url: (deploymentId) => `build/deploy/${deploymentId}/set-env`,
method: 'POST',
body: {
envVariables: JSON.stringify(envVariables),
},
body: JSON.stringify({ envVariables }),
auth
});
}

public getStatusDevMode({ auth, lastHash }: { auth?: AuthObject, lastHash?: string } = {}) {
public getStatusDevMode({ auth, lastHash }: { auth?: AuthObject, lastHash?: string } = {}): Promise<{[key: string]: any}> {
const params = new URLSearchParams();
if (lastHash) {
params.append('lastHash', lastHash);
}

return this.request({
url: (deploymentId) => `devmode/${deploymentId}/status`,
qs: { lastHash },
url: (deploymentId) => `devmode/${deploymentId}/status?${params.toString()}`,
method: 'GET',
auth
});
Expand All @@ -147,7 +171,7 @@ export class CubeCloudClient {
return this.request({
url: (deploymentId) => `devmode/${deploymentId}/token`,
method: 'POST',
body: payload,
body: JSON.stringify(payload),
auth
});
}
Expand Down
7 changes: 6 additions & 1 deletion packages/cubejs-backend-cloud/src/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,19 @@ type DeployHooks = {
onFinally?: Function
};

export interface DeployResponse {
lastHash?: string;
[key: string]: any; // for other properties
}

export class DeployController {
public constructor(
protected readonly cubeCloudClient: CubeCloudClient,
protected readonly hooks: DeployHooks = {}
) {
}

public async deploy(directory: string) {
public async deploy(directory: string): Promise<DeployResponse> {
let result;
const deployDir = new DeployDirectory({ directory });
const fileHashes: any = await deployDir.fileHashes();
Expand Down
2 changes: 2 additions & 0 deletions packages/cubejs-backend-cloud/src/live-preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ export class LivePreviewWatcher {
lastHashTarget: this.lastHash,
uploading: this.uploading,
active: Boolean(this.watcher),
deploymentId: '' as any,
url: '' as any,
};

if (auth) {
Expand Down
5 changes: 2 additions & 3 deletions packages/cubejs-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@
"cli-progress": "^3.10",
"commander": "^2.19.0",
"cross-spawn": "^7.0.1",
"form-data": "^4.0.0",
"fs-extra": "^8.1.0",
"inquirer": "^7.1.0",
"jsonwebtoken": "^9.0.2",
"request": "^2.88.2",
"request-promise": "^4.2.5",
"semver": "^7.6.3",
"node-fetch": "2",
"source-map-support": "^0.5.19"
},
"resolutions": {
Expand All @@ -59,7 +59,6 @@
"@types/jest": "^27",
"@types/jsonwebtoken": "^9.0.2",
"@types/node": "^18",
"@types/request-promise": "^4.1.46",
"@types/semver": "^7.5.8",
"husky": "^4.2.3",
"jest": "^27",
Expand Down
Loading
Loading