@superblocksteam/util 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/component-configs.d.ts +1 -0
- package/dist/component-configs.js +92 -0
- package/dist/constants.d.ts +9 -0
- package/dist/constants.js +29 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +7 -0
- package/dist/login.d.ts +8 -0
- package/dist/login.js +43 -0
- package/dist/resource-configs.d.ts +36 -0
- package/dist/resource-configs.js +80 -0
- package/package.json +17 -0
- package/src/component-configs.ts +97 -0
- package/src/constants.ts +28 -0
- package/src/index.ts +4 -0
- package/src/login.ts +43 -0
- package/src/resource-configs.ts +131 -0
- package/tsconfig.json +13 -0
- package/tsup.config.ts +8 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getComponentConfigs(): Promise<Record<string, any>>;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getComponentConfigs = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
6
|
+
const node_os_1 = tslib_1.__importDefault(require("node:os"));
|
|
7
|
+
const fs = tslib_1.__importStar(require("fs-extra"));
|
|
8
|
+
const constants_1 = require("./constants");
|
|
9
|
+
const child_process_1 = require("child_process");
|
|
10
|
+
const compileTypeScript = (inputFilePath, outputDir) => {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
try {
|
|
13
|
+
const tscPath = require.resolve("typescript/bin/tsc");
|
|
14
|
+
if (tscPath) {
|
|
15
|
+
(0, child_process_1.execFile)(tscPath, [node_path_1.default.resolve(inputFilePath), "--outDir", outputDir, "--jsx", "react-jsx", "--target", "es2019", "--esModuleInterop", "true", "--moduleResolution", "node", "--module", "commonjs"], (error, stdout, stderr) => {
|
|
16
|
+
if (error) {
|
|
17
|
+
// Print any Typescript output to the user, such as errors
|
|
18
|
+
console.log(stdout);
|
|
19
|
+
reject(`Compilation failed: ${error.message}`);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (stderr) {
|
|
23
|
+
reject(`Error during compilation: ${stderr}`);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
resolve("Compilation successful!");
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
reject(new Error("Could not find TypeScript, please install it globally (npm install -g typescript)"));
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
async function getFolderPaths() {
|
|
36
|
+
try {
|
|
37
|
+
const folderPaths = await fs.readdir(constants_1.CUSTOM_COMPONENTS_PATH, {
|
|
38
|
+
withFileTypes: true,
|
|
39
|
+
});
|
|
40
|
+
// filter out any non-directory items
|
|
41
|
+
const directories = folderPaths.filter((dirent) => dirent.isDirectory());
|
|
42
|
+
// map each directory to its path
|
|
43
|
+
const folderPathsArray = directories.map((dirent) => node_path_1.default.resolve(`${constants_1.CUSTOM_COMPONENTS_PATH}/${dirent.name}`));
|
|
44
|
+
return folderPathsArray;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
throw new Error("Could not access component directory, check your permissions");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function getComponentConfigs() {
|
|
51
|
+
const folderPaths = await getFolderPaths();
|
|
52
|
+
const promiseConfigFiles = folderPaths.map(async (ccpath) => {
|
|
53
|
+
try {
|
|
54
|
+
const ret = await fs.readJSON(`${ccpath}/config.json`);
|
|
55
|
+
console.log(`Found component in ${ccpath}`);
|
|
56
|
+
return ret;
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
// Noop because there is a fallback
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
// This is a tad complex to explain this hack but here's the context:
|
|
63
|
+
// We want to be able to hot reload the config.ts file, but we can't import it directly
|
|
64
|
+
// because it is going to get cached in the module cache and we dont have access to it to clear it
|
|
65
|
+
// so instead we copy the file to a new location with a random name and import that
|
|
66
|
+
// this is technically a memory leak, but you shouldnt really have a hot module server running forever
|
|
67
|
+
const rawPath = `${ccpath}/config.ts`;
|
|
68
|
+
const fileName = node_path_1.default.resolve(rawPath);
|
|
69
|
+
const outputDirectory = node_path_1.default.resolve(`${node_os_1.default.tmpdir()}/superblocks/${ccpath}/config.timestamp-${Date.now()}-${Math.random()
|
|
70
|
+
.toString(16)
|
|
71
|
+
.slice(2)}`);
|
|
72
|
+
await compileTypeScript(fileName, outputDirectory);
|
|
73
|
+
console.log(`Typescript compiled to ${ccpath}`);
|
|
74
|
+
const ret = (await Promise.resolve(`${outputDirectory + "/config.js"}`).then(s => tslib_1.__importStar(require(s)))).default;
|
|
75
|
+
console.log(`Found component in ${ccpath}`);
|
|
76
|
+
return ret;
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
console.error(e);
|
|
80
|
+
console.error(e.message);
|
|
81
|
+
throw e;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
const configFiles = (await Promise.all(promiseConfigFiles))
|
|
85
|
+
.filter((file) => file !== null)
|
|
86
|
+
.reduce((acc, config) => {
|
|
87
|
+
acc[config.id] = config;
|
|
88
|
+
return acc;
|
|
89
|
+
}, {});
|
|
90
|
+
return configFiles;
|
|
91
|
+
}
|
|
92
|
+
exports.getComponentConfigs = getComponentConfigs;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const SUPERBLOCKS_HOME_FOLDER_NAME = ".superblocks";
|
|
2
|
+
export declare const TOKEN_CONFIG_PATH = ".superblocks/auth.json";
|
|
3
|
+
export declare const RESOURCE_CONFIG_PATH = ".superblocks/superblocks.json";
|
|
4
|
+
export declare const ROOT_CONFIG_RELATIVE_PATH = "../..";
|
|
5
|
+
export declare const CUSTOM_COMPONENTS_PATH = "components";
|
|
6
|
+
export declare const ERROR_FILE_ACCESS = "FileAccessError";
|
|
7
|
+
export declare class FileAccessError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FileAccessError = exports.ERROR_FILE_ACCESS = exports.CUSTOM_COMPONENTS_PATH = exports.ROOT_CONFIG_RELATIVE_PATH = exports.RESOURCE_CONFIG_PATH = exports.TOKEN_CONFIG_PATH = exports.SUPERBLOCKS_HOME_FOLDER_NAME = void 0;
|
|
4
|
+
exports.SUPERBLOCKS_HOME_FOLDER_NAME = ".superblocks";
|
|
5
|
+
exports.TOKEN_CONFIG_PATH = ".superblocks/auth.json";
|
|
6
|
+
exports.RESOURCE_CONFIG_PATH = ".superblocks/superblocks.json";
|
|
7
|
+
/* It's a relative path from resource's directory to a project's root
|
|
8
|
+
├── apps
|
|
9
|
+
│ ├── <app_name>
|
|
10
|
+
│ │ ├── apis
|
|
11
|
+
│ │ │ ├── <api_name1>
|
|
12
|
+
...
|
|
13
|
+
│ │ │ ├── <api_nameN>
|
|
14
|
+
│ │ ├── application.yaml
|
|
15
|
+
│ │ └── page.yaml
|
|
16
|
+
├── backends
|
|
17
|
+
│ └── <scheduled job|workflow_name>
|
|
18
|
+
│ └── api.yaml
|
|
19
|
+
*/
|
|
20
|
+
exports.ROOT_CONFIG_RELATIVE_PATH = "../..";
|
|
21
|
+
exports.CUSTOM_COMPONENTS_PATH = "components";
|
|
22
|
+
exports.ERROR_FILE_ACCESS = "FileAccessError";
|
|
23
|
+
class FileAccessError extends Error {
|
|
24
|
+
constructor(message) {
|
|
25
|
+
super(message);
|
|
26
|
+
this.name = exports.ERROR_FILE_ACCESS;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
exports.FileAccessError = FileAccessError;
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
tslib_1.__exportStar(require("./constants"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./component-configs"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./login"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./resource-configs"), exports);
|
package/dist/login.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
type TokenWithBaseUrl = {
|
|
2
|
+
token: string;
|
|
3
|
+
superblocksBaseUrl: string;
|
|
4
|
+
};
|
|
5
|
+
export declare function saveApiToken(token: string, superblocksBaseUrl: string): Promise<void>;
|
|
6
|
+
export declare function getLocalTokenWithUrlIfExists(): Promise<TokenWithBaseUrl | undefined>;
|
|
7
|
+
export declare function getLocalTokenWithUrl(): Promise<TokenWithBaseUrl>;
|
|
8
|
+
export {};
|
package/dist/login.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getLocalTokenWithUrl = exports.getLocalTokenWithUrlIfExists = exports.saveApiToken = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const node_os_1 = require("node:os");
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
const fs = tslib_1.__importStar(require("fs-extra"));
|
|
8
|
+
const constants_1 = require("./constants");
|
|
9
|
+
async function saveApiToken(token, superblocksBaseUrl) {
|
|
10
|
+
try {
|
|
11
|
+
await fs.ensureDir((0, node_path_1.join)((0, node_os_1.homedir)(), ".superblocks"));
|
|
12
|
+
await fs.writeJSON((0, node_path_1.join)((0, node_os_1.homedir)(), constants_1.TOKEN_CONFIG_PATH), {
|
|
13
|
+
token,
|
|
14
|
+
superblocksBaseUrl,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
throw new constants_1.FileAccessError("Could not save token");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.saveApiToken = saveApiToken;
|
|
22
|
+
async function getLocalTokenWithUrlIfExists() {
|
|
23
|
+
try {
|
|
24
|
+
return await getLocalTokenWithUrl();
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.getLocalTokenWithUrlIfExists = getLocalTokenWithUrlIfExists;
|
|
31
|
+
async function getLocalTokenWithUrl() {
|
|
32
|
+
try {
|
|
33
|
+
const tokenConfig = await fs.readJSON((0, node_path_1.join)((0, node_os_1.homedir)(), constants_1.TOKEN_CONFIG_PATH));
|
|
34
|
+
return {
|
|
35
|
+
token: tokenConfig.token,
|
|
36
|
+
superblocksBaseUrl: tokenConfig.superblocksBaseUrl,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
throw new Error("No local API key found");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.getLocalTokenWithUrl = getLocalTokenWithUrl;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export type SuperblocksMetadata = {
|
|
2
|
+
cliVersion: string;
|
|
3
|
+
remote: string;
|
|
4
|
+
lastUpdated: number;
|
|
5
|
+
created: number;
|
|
6
|
+
};
|
|
7
|
+
export type VersionedResourceConfig = {
|
|
8
|
+
location: string;
|
|
9
|
+
lastUpdated: number;
|
|
10
|
+
resourceType: "APPLICATION" | "BACKEND";
|
|
11
|
+
};
|
|
12
|
+
export type SuperblocksResourceConfig = {
|
|
13
|
+
id: string;
|
|
14
|
+
};
|
|
15
|
+
export type SuperblocksBackendConfig = SuperblocksResourceConfig & {
|
|
16
|
+
configType: "BACKEND";
|
|
17
|
+
};
|
|
18
|
+
export type SuperblocksApplicationConfig = SuperblocksResourceConfig & {
|
|
19
|
+
configType: "APPLICATION";
|
|
20
|
+
defaultPageId: string;
|
|
21
|
+
apis: Record<string, string>;
|
|
22
|
+
};
|
|
23
|
+
export type SuperblocksMonorepoConfig = {
|
|
24
|
+
configType: "ROOT";
|
|
25
|
+
resources: Record<string, VersionedResourceConfig>;
|
|
26
|
+
metadata: SuperblocksMetadata;
|
|
27
|
+
};
|
|
28
|
+
export type SuperblocksConfig = SuperblocksMonorepoConfig | SuperblocksApplicationConfig | SuperblocksBackendConfig;
|
|
29
|
+
/**
|
|
30
|
+
* Get the Superblocks config file from the current directory (and optionally) hierarchy
|
|
31
|
+
* @param checkParentDir Whether to recursively check the parent directory for a Superblocks config file
|
|
32
|
+
*/
|
|
33
|
+
export declare function getSuperblocksMonorepoConfigJson(checkParentDir?: boolean, pathPrefix?: string): Promise<[SuperblocksMonorepoConfig, string]>;
|
|
34
|
+
export declare function getSuperblocksApplicationConfigJson(): Promise<SuperblocksApplicationConfig>;
|
|
35
|
+
export declare function getSuperblocksBackendConfigJson(): Promise<SuperblocksBackendConfig>;
|
|
36
|
+
export declare function getSuperblocksResourceConfigIfExists(): Promise<SuperblocksResourceConfig | undefined>;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getSuperblocksResourceConfigIfExists = exports.getSuperblocksBackendConfigJson = exports.getSuperblocksApplicationConfigJson = exports.getSuperblocksMonorepoConfigJson = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const fs = tslib_1.__importStar(require("fs-extra"));
|
|
6
|
+
const constants_1 = require("./constants");
|
|
7
|
+
/**
|
|
8
|
+
* Get the Superblocks config file from the current directory (and optionally) hierarchy
|
|
9
|
+
* @param checkParentDir Whether to recursively check the parent directory for a Superblocks config file
|
|
10
|
+
*/
|
|
11
|
+
async function getSuperblocksMonorepoConfigJson(checkParentDir = false, pathPrefix = "") {
|
|
12
|
+
let superblocksConfig;
|
|
13
|
+
if (pathPrefix && !fs.existsSync(pathPrefix)) {
|
|
14
|
+
throw new Error("No Superblocks config file found in current directory hierarchy " +
|
|
15
|
+
pathPrefix);
|
|
16
|
+
}
|
|
17
|
+
try {
|
|
18
|
+
superblocksConfig = await fs.readJSON(pathPrefix + constants_1.RESOURCE_CONFIG_PATH);
|
|
19
|
+
if (superblocksConfig.configType !== "ROOT") {
|
|
20
|
+
throw new Error("Not the root Superblocks config file");
|
|
21
|
+
}
|
|
22
|
+
return [
|
|
23
|
+
superblocksConfig,
|
|
24
|
+
pathPrefix + constants_1.RESOURCE_CONFIG_PATH,
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
if (!checkParentDir) {
|
|
29
|
+
// no superblocks config file found
|
|
30
|
+
throw new Error("No Superblocks config file found in current directory " +
|
|
31
|
+
pathPrefix +
|
|
32
|
+
constants_1.RESOURCE_CONFIG_PATH);
|
|
33
|
+
}
|
|
34
|
+
return getSuperblocksMonorepoConfigJson(true, "../" + pathPrefix);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.getSuperblocksMonorepoConfigJson = getSuperblocksMonorepoConfigJson;
|
|
38
|
+
async function getSuperblocksApplicationConfigJson() {
|
|
39
|
+
let superblocksConfig;
|
|
40
|
+
try {
|
|
41
|
+
superblocksConfig = await fs.readJSON(constants_1.RESOURCE_CONFIG_PATH);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// no superblocks config file found
|
|
45
|
+
throw new Error("This command must be run within a Superblocks app directory.");
|
|
46
|
+
}
|
|
47
|
+
if (superblocksConfig.configType !== "APPLICATION") {
|
|
48
|
+
throw new Error("Please execute this command within a Superblocks application directory.");
|
|
49
|
+
}
|
|
50
|
+
return superblocksConfig;
|
|
51
|
+
}
|
|
52
|
+
exports.getSuperblocksApplicationConfigJson = getSuperblocksApplicationConfigJson;
|
|
53
|
+
async function getSuperblocksBackendConfigJson() {
|
|
54
|
+
let superblocksConfig;
|
|
55
|
+
try {
|
|
56
|
+
superblocksConfig = await fs.readJSON(constants_1.RESOURCE_CONFIG_PATH);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// no superblocks config file found
|
|
60
|
+
throw new Error("This command must be run within a Superblocks backend resource (workflow/job) directory.");
|
|
61
|
+
}
|
|
62
|
+
if (superblocksConfig.configType !== "BACKEND") {
|
|
63
|
+
throw new Error("Please execute this command within a Superblocks backend resource (workflow/job) directory.");
|
|
64
|
+
}
|
|
65
|
+
return superblocksConfig;
|
|
66
|
+
}
|
|
67
|
+
exports.getSuperblocksBackendConfigJson = getSuperblocksBackendConfigJson;
|
|
68
|
+
async function getSuperblocksResourceConfigIfExists() {
|
|
69
|
+
let config;
|
|
70
|
+
try {
|
|
71
|
+
config = await getSuperblocksApplicationConfigJson();
|
|
72
|
+
}
|
|
73
|
+
catch { }
|
|
74
|
+
try {
|
|
75
|
+
config = await getSuperblocksBackendConfigJson();
|
|
76
|
+
}
|
|
77
|
+
catch { }
|
|
78
|
+
return config;
|
|
79
|
+
}
|
|
80
|
+
exports.getSuperblocksResourceConfigIfExists = getSuperblocksResourceConfigIfExists;
|
package/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@superblocksteam/util",
|
|
3
|
+
"version": "0.0.11",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"homepage": "https://www.superblocks.com",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "tsc --watch",
|
|
8
|
+
"build": "tsc --build",
|
|
9
|
+
"clean": "npm run clean:build && rm -rf node_modules",
|
|
10
|
+
"clean:build": "tsc --build --clean && rm -rf dist tsconfig.tsbuildinfo"
|
|
11
|
+
},
|
|
12
|
+
"license": "Superblocks Community Software License",
|
|
13
|
+
"description": "",
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"typescript": "^5.0.4"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import * as fs from "fs-extra";
|
|
4
|
+
import { CUSTOM_COMPONENTS_PATH } from "./constants";
|
|
5
|
+
import { execFile } from "child_process";
|
|
6
|
+
|
|
7
|
+
const compileTypeScript = (inputFilePath: string, outputDir: string) => {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
try {
|
|
10
|
+
const tscPath = require.resolve("typescript/bin/tsc");
|
|
11
|
+
if (tscPath) {
|
|
12
|
+
execFile(
|
|
13
|
+
tscPath,
|
|
14
|
+
[path.resolve(inputFilePath), "--outDir", outputDir, "--jsx", "react-jsx", "--target", "es2019", "--esModuleInterop", "true", "--moduleResolution", "node", "--module", "commonjs"],
|
|
15
|
+
(error, stdout, stderr) => {
|
|
16
|
+
if (error) {
|
|
17
|
+
// Print any Typescript output to the user, such as errors
|
|
18
|
+
console.log(stdout);
|
|
19
|
+
reject(`Compilation failed: ${error.message}`);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (stderr) {
|
|
23
|
+
reject(`Error during compilation: ${stderr}`);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
resolve("Compilation successful!");
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
} catch (e) {
|
|
31
|
+
reject(new Error("Could not find TypeScript, please install it globally (npm install -g typescript)"));
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
async function getFolderPaths() {
|
|
37
|
+
try {
|
|
38
|
+
const folderPaths = await fs.readdir(CUSTOM_COMPONENTS_PATH, {
|
|
39
|
+
withFileTypes: true,
|
|
40
|
+
});
|
|
41
|
+
// filter out any non-directory items
|
|
42
|
+
const directories = folderPaths.filter((dirent) => dirent.isDirectory());
|
|
43
|
+
// map each directory to its path
|
|
44
|
+
const folderPathsArray = directories.map((dirent) =>
|
|
45
|
+
path.resolve(`${CUSTOM_COMPONENTS_PATH}/${dirent.name}`)
|
|
46
|
+
);
|
|
47
|
+
return folderPathsArray;
|
|
48
|
+
} catch {
|
|
49
|
+
throw new Error(
|
|
50
|
+
"Could not access component directory, check your permissions"
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export async function getComponentConfigs(): Promise<Record<string, any>> {
|
|
56
|
+
const folderPaths = await getFolderPaths();
|
|
57
|
+
const promiseConfigFiles = folderPaths.map(async (ccpath) => {
|
|
58
|
+
try {
|
|
59
|
+
const ret = await fs.readJSON(`${ccpath}/config.json`);
|
|
60
|
+
console.log(`Found component in ${ccpath}`);
|
|
61
|
+
return ret;
|
|
62
|
+
} catch (e: any) {
|
|
63
|
+
// Noop because there is a fallback
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
// This is a tad complex to explain this hack but here's the context:
|
|
68
|
+
// We want to be able to hot reload the config.ts file, but we can't import it directly
|
|
69
|
+
// because it is going to get cached in the module cache and we dont have access to it to clear it
|
|
70
|
+
// so instead we copy the file to a new location with a random name and import that
|
|
71
|
+
// this is technically a memory leak, but you shouldnt really have a hot module server running forever
|
|
72
|
+
const rawPath = `${ccpath}/config.ts`;
|
|
73
|
+
const fileName = path.resolve(rawPath);
|
|
74
|
+
const outputDirectory = path.resolve(
|
|
75
|
+
`${os.tmpdir()}/superblocks/${ccpath}/config.timestamp-${Date.now()}-${Math.random()
|
|
76
|
+
.toString(16)
|
|
77
|
+
.slice(2)}`
|
|
78
|
+
);
|
|
79
|
+
await compileTypeScript(fileName, outputDirectory);
|
|
80
|
+
console.log(`Typescript compiled to ${ccpath}`);
|
|
81
|
+
const ret = (await import(outputDirectory + "/config.js")).default;
|
|
82
|
+
console.log(`Found component in ${ccpath}`);
|
|
83
|
+
return ret;
|
|
84
|
+
} catch (e: any) {
|
|
85
|
+
console.error(e);
|
|
86
|
+
console.error(e.message);
|
|
87
|
+
throw e;
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
const configFiles = (await Promise.all(promiseConfigFiles))
|
|
91
|
+
.filter((file) => file !== null)
|
|
92
|
+
.reduce((acc, config) => {
|
|
93
|
+
acc[config.id] = config;
|
|
94
|
+
return acc;
|
|
95
|
+
}, {});
|
|
96
|
+
return configFiles;
|
|
97
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const SUPERBLOCKS_HOME_FOLDER_NAME = ".superblocks";
|
|
2
|
+
export const TOKEN_CONFIG_PATH = ".superblocks/auth.json";
|
|
3
|
+
export const RESOURCE_CONFIG_PATH = ".superblocks/superblocks.json";
|
|
4
|
+
|
|
5
|
+
/* It's a relative path from resource's directory to a project's root
|
|
6
|
+
├── apps
|
|
7
|
+
│ ├── <app_name>
|
|
8
|
+
│ │ ├── apis
|
|
9
|
+
│ │ │ ├── <api_name1>
|
|
10
|
+
...
|
|
11
|
+
│ │ │ ├── <api_nameN>
|
|
12
|
+
│ │ ├── application.yaml
|
|
13
|
+
│ │ └── page.yaml
|
|
14
|
+
├── backends
|
|
15
|
+
│ └── <scheduled job|workflow_name>
|
|
16
|
+
│ └── api.yaml
|
|
17
|
+
*/
|
|
18
|
+
export const ROOT_CONFIG_RELATIVE_PATH = "../..";
|
|
19
|
+
|
|
20
|
+
export const CUSTOM_COMPONENTS_PATH = "components";
|
|
21
|
+
|
|
22
|
+
export const ERROR_FILE_ACCESS = "FileAccessError";
|
|
23
|
+
export class FileAccessError extends Error {
|
|
24
|
+
constructor(message: string) {
|
|
25
|
+
super(message);
|
|
26
|
+
this.name = ERROR_FILE_ACCESS;
|
|
27
|
+
}
|
|
28
|
+
}
|
package/src/index.ts
ADDED
package/src/login.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import * as fs from "fs-extra";
|
|
4
|
+
import { FileAccessError, TOKEN_CONFIG_PATH } from "./constants";
|
|
5
|
+
|
|
6
|
+
type TokenWithBaseUrl = {
|
|
7
|
+
token: string;
|
|
8
|
+
superblocksBaseUrl: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export async function saveApiToken(token: string, superblocksBaseUrl: string) {
|
|
12
|
+
try {
|
|
13
|
+
await fs.ensureDir(join(homedir(), ".superblocks"));
|
|
14
|
+
await fs.writeJSON(join(homedir(), TOKEN_CONFIG_PATH), {
|
|
15
|
+
token,
|
|
16
|
+
superblocksBaseUrl,
|
|
17
|
+
});
|
|
18
|
+
} catch {
|
|
19
|
+
throw new FileAccessError("Could not save token");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function getLocalTokenWithUrlIfExists(): Promise<
|
|
24
|
+
TokenWithBaseUrl | undefined
|
|
25
|
+
> {
|
|
26
|
+
try {
|
|
27
|
+
return await getLocalTokenWithUrl();
|
|
28
|
+
} catch {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function getLocalTokenWithUrl(): Promise<TokenWithBaseUrl> {
|
|
34
|
+
try {
|
|
35
|
+
const tokenConfig = await fs.readJSON(join(homedir(), TOKEN_CONFIG_PATH));
|
|
36
|
+
return {
|
|
37
|
+
token: tokenConfig.token as string,
|
|
38
|
+
superblocksBaseUrl: tokenConfig.superblocksBaseUrl as string,
|
|
39
|
+
};
|
|
40
|
+
} catch {
|
|
41
|
+
throw new Error("No local API key found");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import * as fs from "fs-extra";
|
|
2
|
+
import { RESOURCE_CONFIG_PATH } from "./constants";
|
|
3
|
+
|
|
4
|
+
export type SuperblocksMetadata = {
|
|
5
|
+
cliVersion: string;
|
|
6
|
+
remote: string;
|
|
7
|
+
lastUpdated: number;
|
|
8
|
+
created: number;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type VersionedResourceConfig = {
|
|
12
|
+
location: string;
|
|
13
|
+
lastUpdated: number;
|
|
14
|
+
resourceType: "APPLICATION" | "BACKEND";
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type SuperblocksResourceConfig = {
|
|
18
|
+
id: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type SuperblocksBackendConfig = SuperblocksResourceConfig & {
|
|
22
|
+
configType: "BACKEND";
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type SuperblocksApplicationConfig = SuperblocksResourceConfig & {
|
|
26
|
+
configType: "APPLICATION";
|
|
27
|
+
defaultPageId: string;
|
|
28
|
+
apis: Record<string, string>;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type SuperblocksMonorepoConfig = {
|
|
32
|
+
configType: "ROOT";
|
|
33
|
+
resources: Record<string, VersionedResourceConfig>;
|
|
34
|
+
metadata: SuperblocksMetadata;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type SuperblocksConfig =
|
|
38
|
+
| SuperblocksMonorepoConfig
|
|
39
|
+
| SuperblocksApplicationConfig
|
|
40
|
+
| SuperblocksBackendConfig;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get the Superblocks config file from the current directory (and optionally) hierarchy
|
|
44
|
+
* @param checkParentDir Whether to recursively check the parent directory for a Superblocks config file
|
|
45
|
+
*/
|
|
46
|
+
export async function getSuperblocksMonorepoConfigJson(
|
|
47
|
+
checkParentDir = false,
|
|
48
|
+
pathPrefix = ""
|
|
49
|
+
): Promise<[SuperblocksMonorepoConfig, string]> {
|
|
50
|
+
let superblocksConfig;
|
|
51
|
+
if (pathPrefix && !fs.existsSync(pathPrefix)) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
"No Superblocks config file found in current directory hierarchy " +
|
|
54
|
+
pathPrefix
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
superblocksConfig = await fs.readJSON(pathPrefix + RESOURCE_CONFIG_PATH);
|
|
60
|
+
if (superblocksConfig.configType !== "ROOT") {
|
|
61
|
+
throw new Error("Not the root Superblocks config file");
|
|
62
|
+
}
|
|
63
|
+
return [
|
|
64
|
+
superblocksConfig as SuperblocksMonorepoConfig,
|
|
65
|
+
pathPrefix + RESOURCE_CONFIG_PATH,
|
|
66
|
+
];
|
|
67
|
+
} catch {
|
|
68
|
+
if (!checkParentDir) {
|
|
69
|
+
// no superblocks config file found
|
|
70
|
+
throw new Error(
|
|
71
|
+
"No Superblocks config file found in current directory " +
|
|
72
|
+
pathPrefix +
|
|
73
|
+
RESOURCE_CONFIG_PATH
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return getSuperblocksMonorepoConfigJson(true, "../" + pathPrefix);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export async function getSuperblocksApplicationConfigJson(): Promise<SuperblocksApplicationConfig> {
|
|
81
|
+
let superblocksConfig;
|
|
82
|
+
try {
|
|
83
|
+
superblocksConfig = await fs.readJSON(RESOURCE_CONFIG_PATH);
|
|
84
|
+
} catch {
|
|
85
|
+
// no superblocks config file found
|
|
86
|
+
throw new Error(
|
|
87
|
+
"This command must be run within a Superblocks app directory."
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (superblocksConfig.configType !== "APPLICATION") {
|
|
92
|
+
throw new Error(
|
|
93
|
+
"Please execute this command within a Superblocks application directory."
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return superblocksConfig as SuperblocksApplicationConfig;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export async function getSuperblocksBackendConfigJson(): Promise<SuperblocksBackendConfig> {
|
|
101
|
+
let superblocksConfig;
|
|
102
|
+
try {
|
|
103
|
+
superblocksConfig = await fs.readJSON(RESOURCE_CONFIG_PATH);
|
|
104
|
+
} catch {
|
|
105
|
+
// no superblocks config file found
|
|
106
|
+
throw new Error(
|
|
107
|
+
"This command must be run within a Superblocks backend resource (workflow/job) directory."
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (superblocksConfig.configType !== "BACKEND") {
|
|
112
|
+
throw new Error(
|
|
113
|
+
"Please execute this command within a Superblocks backend resource (workflow/job) directory."
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return superblocksConfig as SuperblocksBackendConfig;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export async function getSuperblocksResourceConfigIfExists(): Promise<
|
|
121
|
+
SuperblocksResourceConfig | undefined
|
|
122
|
+
> {
|
|
123
|
+
let config: SuperblocksResourceConfig | undefined;
|
|
124
|
+
try {
|
|
125
|
+
config = await getSuperblocksApplicationConfigJson();
|
|
126
|
+
} catch {}
|
|
127
|
+
try {
|
|
128
|
+
config = await getSuperblocksBackendConfigJson();
|
|
129
|
+
} catch {}
|
|
130
|
+
return config;
|
|
131
|
+
}
|
package/tsconfig.json
ADDED