@superblocksteam/cli 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/README.md +175 -0
- package/assets/custom-components/.eslintrc.js +26 -0
- package/assets/custom-components/package.json +26 -0
- package/assets/custom-components/tsconfig.json +13 -0
- package/bin/dev +8 -0
- package/bin/dev.cmd +3 -0
- package/bin/run +8 -0
- package/bin/run.cmd +3 -0
- package/dist/commands/components/create.d.ts +5 -0
- package/dist/commands/components/create.js +146 -0
- package/dist/commands/components/register.d.ts +6 -0
- package/dist/commands/components/register.js +38 -0
- package/dist/commands/components/upload.d.ts +6 -0
- package/dist/commands/components/upload.js +151 -0
- package/dist/commands/components/watch.d.ts +7 -0
- package/dist/commands/components/watch.js +101 -0
- package/dist/commands/init.d.ts +15 -0
- package/dist/commands/init.js +238 -0
- package/dist/commands/login.d.ts +9 -0
- package/dist/commands/login.js +66 -0
- package/dist/commands/pull.d.ts +14 -0
- package/dist/commands/pull.js +167 -0
- package/dist/common/authenticated-command.d.ts +14 -0
- package/dist/common/authenticated-command.js +58 -0
- package/dist/common/defaults/create-component-defaults.d.ts +9 -0
- package/dist/common/defaults/create-component-defaults.js +60 -0
- package/dist/common/types.d.ts +7 -0
- package/dist/common/types.js +2 -0
- package/dist/common/version-control.d.ts +21 -0
- package/dist/common/version-control.js +166 -0
- package/dist/exportedTypes.d.ts +20 -0
- package/dist/exportedTypes.js +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +7 -0
- package/dist/util/identifiers.d.ts +7 -0
- package/dist/util/identifiers.js +37 -0
- package/dist/util/prompt.d.ts +7 -0
- package/dist/util/prompt.js +33 -0
- package/dist/util/types.d.ts +9 -0
- package/dist/util/types.js +26 -0
- package/oclif.manifest.json +151 -0
- package/package.json +97 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.healthEndpointMiddleware = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const core_1 = require("@oclif/core");
|
|
6
|
+
const util_1 = require("@superblocksteam/util");
|
|
7
|
+
const vite_custom_component_reload_plugin_1 = require("@superblocksteam/vite-custom-component-reload-plugin");
|
|
8
|
+
const plugin_react_1 = tslib_1.__importDefault(require("@vitejs/plugin-react"));
|
|
9
|
+
const colorette_1 = require("colorette");
|
|
10
|
+
const vite_1 = require("vite");
|
|
11
|
+
const vite_plugin_externals_1 = require("vite-plugin-externals");
|
|
12
|
+
const authenticated_command_1 = require("../../common/authenticated-command");
|
|
13
|
+
function healthEndpointMiddleware() {
|
|
14
|
+
return {
|
|
15
|
+
name: "health-endpoint-middleware",
|
|
16
|
+
configureServer: (server) => {
|
|
17
|
+
server.middlewares.use("/health", (req, res) => {
|
|
18
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
19
|
+
res.setHeader("Content-Type", "application/json");
|
|
20
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
21
|
+
const response = {
|
|
22
|
+
status: "up",
|
|
23
|
+
uptime: Math.floor(process.uptime()),
|
|
24
|
+
};
|
|
25
|
+
res.write(JSON.stringify(response) + "\n");
|
|
26
|
+
res.end();
|
|
27
|
+
});
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
exports.healthEndpointMiddleware = healthEndpointMiddleware;
|
|
32
|
+
class Watch extends authenticated_command_1.AuthenticatedApplicationCommand {
|
|
33
|
+
async run() {
|
|
34
|
+
core_1.ux.action.start("Registering components...");
|
|
35
|
+
const components = await (0, util_1.getComponentConfigs)();
|
|
36
|
+
await this.getSdk().registerComponents(this.applicationConfig.id, components);
|
|
37
|
+
core_1.ux.action.stop();
|
|
38
|
+
this.log((0, colorette_1.yellow)("Remember to refresh your application to see any newly registered components."));
|
|
39
|
+
this.log();
|
|
40
|
+
this.log((0, colorette_1.green)(`Visit ${await this.getBaseUrl()} and access your application in edit mode to see your components! 🐨`));
|
|
41
|
+
const port = 3002;
|
|
42
|
+
const editModeUrl = await this.getEditModeUrl();
|
|
43
|
+
const viteLogger = (0, vite_1.createLogger)();
|
|
44
|
+
viteLogger.info = (message) => {
|
|
45
|
+
this.log(message);
|
|
46
|
+
};
|
|
47
|
+
viteLogger.warn = (msg) => {
|
|
48
|
+
this.log((0, colorette_1.yellow)(msg));
|
|
49
|
+
};
|
|
50
|
+
viteLogger.warnOnce = (msg) => {
|
|
51
|
+
this.log((0, colorette_1.yellow)(msg));
|
|
52
|
+
};
|
|
53
|
+
viteLogger.error = (msg) => {
|
|
54
|
+
this.log((0, colorette_1.red)(msg));
|
|
55
|
+
};
|
|
56
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
57
|
+
viteLogger.clearScreen = () => { };
|
|
58
|
+
await (async () => {
|
|
59
|
+
const server = await (0, vite_1.createServer)({
|
|
60
|
+
configFile: false,
|
|
61
|
+
build: {
|
|
62
|
+
rollupOptions: {
|
|
63
|
+
input: [
|
|
64
|
+
// eslint-disable-next-line no-warning-comments
|
|
65
|
+
/* TODO */
|
|
66
|
+
],
|
|
67
|
+
preserveEntrySignatures: "strict",
|
|
68
|
+
output: {
|
|
69
|
+
entryFileNames: "[name].js",
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
copyPublicDir: true,
|
|
73
|
+
write: true,
|
|
74
|
+
},
|
|
75
|
+
base: `http://localhost:${port}`,
|
|
76
|
+
server: {
|
|
77
|
+
port,
|
|
78
|
+
},
|
|
79
|
+
customLogger: viteLogger,
|
|
80
|
+
plugins: [
|
|
81
|
+
healthEndpointMiddleware(),
|
|
82
|
+
(0, plugin_react_1.default)(),
|
|
83
|
+
(0, vite_plugin_externals_1.viteExternalsPlugin)({
|
|
84
|
+
react: "React",
|
|
85
|
+
"react-dom": "ReactDOM",
|
|
86
|
+
}),
|
|
87
|
+
(0, vite_custom_component_reload_plugin_1.appendHotReloadEventPlugin)(),
|
|
88
|
+
],
|
|
89
|
+
});
|
|
90
|
+
await server.listen();
|
|
91
|
+
this.log((0, colorette_1.green)(`Local server started at port ${port}`));
|
|
92
|
+
this.log((0, colorette_1.green)(`Visit your application at:`));
|
|
93
|
+
this.log();
|
|
94
|
+
this.log((0, colorette_1.bgGreen)((0, colorette_1.bold)((0, colorette_1.white)(`${editModeUrl}?devMode=true`))));
|
|
95
|
+
this.log();
|
|
96
|
+
this.log((0, colorette_1.yellow)("Remember to refresh your already open Application page and turn on local development in Superblocks to connect to your local server!"));
|
|
97
|
+
})();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
Watch.description = "watch for changes to your custom components";
|
|
101
|
+
exports.default = Watch;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AuthenticatedCommand } from "../common/authenticated-command";
|
|
2
|
+
export default class Initialize extends AuthenticatedCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
mode: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
|
|
7
|
+
};
|
|
8
|
+
static args: {
|
|
9
|
+
resourceUrl: import("@oclif/core/lib/interfaces/parser").Arg<string | undefined, Record<string, unknown>>;
|
|
10
|
+
};
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
private createTasks;
|
|
13
|
+
private getResourcesToInitialize;
|
|
14
|
+
private findDuplicates;
|
|
15
|
+
}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const core_1 = require("@oclif/core");
|
|
5
|
+
const util_1 = require("@superblocksteam/util");
|
|
6
|
+
const fs = tslib_1.__importStar(require("fs-extra"));
|
|
7
|
+
const listr2_1 = require("listr2");
|
|
8
|
+
const lodash_1 = require("lodash");
|
|
9
|
+
const authenticated_command_1 = require("../common/authenticated-command");
|
|
10
|
+
const version_control_1 = require("../common/version-control");
|
|
11
|
+
class Initialize extends authenticated_command_1.AuthenticatedCommand {
|
|
12
|
+
async run() {
|
|
13
|
+
const { flags, args } = await this.parse(Initialize);
|
|
14
|
+
const tasks = this.createTasks(flags, args);
|
|
15
|
+
try {
|
|
16
|
+
await tasks.run();
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
this.error(error.message);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
createTasks(flags, args) {
|
|
23
|
+
const tasks = new listr2_1.Listr([
|
|
24
|
+
{
|
|
25
|
+
title: "Checking for existing Superblocks project...",
|
|
26
|
+
task: async (ctx) => {
|
|
27
|
+
ctx.fetchedResources = {};
|
|
28
|
+
ctx.writtenResources = {};
|
|
29
|
+
ctx.now = Date.now();
|
|
30
|
+
try {
|
|
31
|
+
ctx.existingSuperblocksConfig = (await (0, util_1.getSuperblocksMonorepoConfigJson)())[0];
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// no existing superblocks config
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
title: "Fetching applications, workflows and scheduled jobs...",
|
|
40
|
+
task: (ctx, task) => task.newListr([
|
|
41
|
+
{
|
|
42
|
+
title: "Fetching applications...",
|
|
43
|
+
task: async (ctx, task) => {
|
|
44
|
+
if (args.resourceUrl) {
|
|
45
|
+
task.skip("Skipping fetching applications");
|
|
46
|
+
}
|
|
47
|
+
// applications choices
|
|
48
|
+
const applications = await this.getSdk().fetchApplications();
|
|
49
|
+
for (const app of applications) {
|
|
50
|
+
if (app.isEditable) {
|
|
51
|
+
0;
|
|
52
|
+
ctx.fetchedResources[app.id] = {
|
|
53
|
+
resourceType: "APPLICATION",
|
|
54
|
+
name: app.name,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
task.title += `: completed`;
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
]),
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
title: "Selecting resources to initialize...",
|
|
65
|
+
task: async (ctx, task) => {
|
|
66
|
+
const viewMode = await (0, version_control_1.getMode)(task, flags.mode);
|
|
67
|
+
ctx.viewMode = viewMode;
|
|
68
|
+
const resourceIdsToInitialize = await this.getResourcesToInitialize(ctx, task, args);
|
|
69
|
+
ctx.resourceIdsToInitialize = resourceIdsToInitialize;
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
title: "Writing resources to a disk...",
|
|
74
|
+
task: async (ctx, task) => {
|
|
75
|
+
const subtasks = [];
|
|
76
|
+
const now = Date.now();
|
|
77
|
+
for (const resourceId of ctx.resourceIdsToInitialize) {
|
|
78
|
+
const resource = ctx.fetchedResources[resourceId];
|
|
79
|
+
switch (resource.resourceType) {
|
|
80
|
+
case "APPLICATION": {
|
|
81
|
+
subtasks.push({
|
|
82
|
+
title: `Fetching application ${resource.name}...`,
|
|
83
|
+
task: async (_ctx, task) => {
|
|
84
|
+
const application = await this.getSdk().fetchApplication(resourceId, ctx.viewMode);
|
|
85
|
+
task.title += `: fetched`;
|
|
86
|
+
ctx.writtenResources[resourceId] =
|
|
87
|
+
await (0, version_control_1.writeResourceToDisk)("APPLICATION", resourceId, application, now, process.cwd());
|
|
88
|
+
task.title += `: done`;
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
case "BACKEND": {
|
|
94
|
+
subtasks.push({
|
|
95
|
+
title: `Fetching backend ${resource.name}...`,
|
|
96
|
+
task: async (_ctx, task) => {
|
|
97
|
+
const backend = await this.getSdk().fetchApi(resourceId, ctx.viewMode);
|
|
98
|
+
task.title += `: fetched`;
|
|
99
|
+
ctx.writtenResources[resourceId] =
|
|
100
|
+
await (0, version_control_1.writeResourceToDisk)("BACKEND", resourceId, backend, now, process.cwd());
|
|
101
|
+
task.title += `: done`;
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
default: {
|
|
107
|
+
this.error(`Unsupported resource type, resurce: ${JSON.stringify(resource)}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return task.newListr(subtasks, {
|
|
112
|
+
concurrent: true,
|
|
113
|
+
});
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
title: "Updating Superblocks project file...",
|
|
118
|
+
task: async (ctx) => {
|
|
119
|
+
var _a, _b, _c, _d;
|
|
120
|
+
const superblocksConfig = {
|
|
121
|
+
configType: "ROOT",
|
|
122
|
+
resources: {},
|
|
123
|
+
metadata: {
|
|
124
|
+
cliVersion: this.config.version,
|
|
125
|
+
remote: this.getSdk().superblocksBaseUrl,
|
|
126
|
+
lastUpdated: ctx.now,
|
|
127
|
+
created: (_b = (_a = ctx.existingSuperblocksConfig) === null || _a === void 0 ? void 0 : _a.metadata.created) !== null && _b !== void 0 ? _b : ctx.now,
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
superblocksConfig.metadata.lastUpdated = ctx.now;
|
|
131
|
+
// new resources
|
|
132
|
+
for (const [resourceId, resource] of Object.entries(ctx.writtenResources)) {
|
|
133
|
+
superblocksConfig.resources[resourceId] = resource;
|
|
134
|
+
}
|
|
135
|
+
// existing resources
|
|
136
|
+
for (const [resourceId, resource] of Object.entries((_d = (_c = ctx.existingSuperblocksConfig) === null || _c === void 0 ? void 0 : _c.resources) !== null && _d !== void 0 ? _d : {})) {
|
|
137
|
+
superblocksConfig.resources[resourceId] = resource;
|
|
138
|
+
}
|
|
139
|
+
if (!(await fs.exists(util_1.SUPERBLOCKS_HOME_FOLDER_NAME))) {
|
|
140
|
+
await fs.mkdir(util_1.SUPERBLOCKS_HOME_FOLDER_NAME);
|
|
141
|
+
}
|
|
142
|
+
// create superblocks.json file
|
|
143
|
+
await fs.writeFile(util_1.RESOURCE_CONFIG_PATH, JSON.stringify((0, version_control_1.sortByKey)(superblocksConfig), null, 2));
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
], {
|
|
147
|
+
concurrent: false,
|
|
148
|
+
});
|
|
149
|
+
return tasks;
|
|
150
|
+
}
|
|
151
|
+
async getResourcesToInitialize(ctx, task, args) {
|
|
152
|
+
var _a, _b;
|
|
153
|
+
if (args.resourceUrl) {
|
|
154
|
+
try {
|
|
155
|
+
const resourceUrl = new URL(args.resourceUrl);
|
|
156
|
+
if (resourceUrl.pathname.startsWith("/applications") ||
|
|
157
|
+
resourceUrl.pathname.startsWith("/workflows") ||
|
|
158
|
+
resourceUrl.pathname.startsWith("/scheduled-jobs")) {
|
|
159
|
+
return [resourceUrl.pathname.split("/")[2]];
|
|
160
|
+
}
|
|
161
|
+
throw new Error(`Failed to parse resource URL: ${args.resourceUrl}`);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
throw new Error(`Invalid resource URL: ${args.resourceUrl}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
const choices = [];
|
|
169
|
+
const initialSelections = [];
|
|
170
|
+
let counter = 0;
|
|
171
|
+
for (const [resourceId, resource] of Object.entries(ctx.fetchedResources)) {
|
|
172
|
+
choices.push({
|
|
173
|
+
name: resourceId,
|
|
174
|
+
message: `${resource.name} (${resource.resourceType})`,
|
|
175
|
+
disabled: (_a = ctx.existingSuperblocksConfig) === null || _a === void 0 ? void 0 : _a.resources[resourceId],
|
|
176
|
+
});
|
|
177
|
+
if ((_b = ctx.existingSuperblocksConfig) === null || _b === void 0 ? void 0 : _b.resources[resourceId]) {
|
|
178
|
+
initialSelections.push(counter);
|
|
179
|
+
}
|
|
180
|
+
counter++;
|
|
181
|
+
}
|
|
182
|
+
const resourceIdsToInitialize = await task.prompt([
|
|
183
|
+
{
|
|
184
|
+
type: "AutoComplete",
|
|
185
|
+
name: "resourceIdsToInitialize",
|
|
186
|
+
message: `Select resources to initialize (${version_control_1.MULTI_SELECT_PROMPT_HELP})`,
|
|
187
|
+
choices: choices,
|
|
188
|
+
initial: initialSelections,
|
|
189
|
+
multiple: true,
|
|
190
|
+
validate: version_control_1.atLeastOneSelection,
|
|
191
|
+
prefix: "▸",
|
|
192
|
+
indicator: "◉",
|
|
193
|
+
},
|
|
194
|
+
]);
|
|
195
|
+
const duplicates = await this.findDuplicates(resourceIdsToInitialize, ctx.fetchedResources);
|
|
196
|
+
if (!(0, lodash_1.isEmpty)(duplicates)) {
|
|
197
|
+
this.error(`Duplicate resources selected: ${duplicates
|
|
198
|
+
.map((duplicate) => `${duplicate.name} (${duplicate.resourceType}) id: ${duplicate.id}`)
|
|
199
|
+
.join(", ")}. Please make sure to select unique resources or rename them so that they have unique names.`);
|
|
200
|
+
}
|
|
201
|
+
// filter out disabled resources
|
|
202
|
+
return resourceIdsToInitialize.filter((resourceId) => { var _a; return !((_a = ctx.existingSuperblocksConfig) === null || _a === void 0 ? void 0 : _a.resources[resourceId]); });
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
async findDuplicates(selectedResourcesIds, resources) {
|
|
206
|
+
const selectedResources = selectedResourcesIds
|
|
207
|
+
.map((id) => {
|
|
208
|
+
return { ...resources[id], id };
|
|
209
|
+
})
|
|
210
|
+
.filter((resource) => resource !== undefined);
|
|
211
|
+
const countResourceNamesByType = {};
|
|
212
|
+
for (const resource of selectedResources) {
|
|
213
|
+
if (!countResourceNamesByType[resource.resourceType]) {
|
|
214
|
+
countResourceNamesByType[resource.resourceType] = {};
|
|
215
|
+
}
|
|
216
|
+
if (countResourceNamesByType[resource.resourceType][resource.name]) {
|
|
217
|
+
countResourceNamesByType[resource.resourceType][resource.name] += 1;
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
countResourceNamesByType[resource.resourceType][resource.name] = 1;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return selectedResources.filter((resource) => countResourceNamesByType[resource.resourceType][resource.name] > 1);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
Initialize.description = "Interactively configure the current directory as a Superblocks project or initialize new services in an already configured Superblocks project directory";
|
|
227
|
+
Initialize.examples = [
|
|
228
|
+
"<%= config.bin %> <%= command.id %>",
|
|
229
|
+
"<%= config.bin %> <%= command.id %> https://app.superblocks.com/applications/11111111-1111-1111-1111-111111111111/pages/22222222-2222-2222-2222-222222222222",
|
|
230
|
+
];
|
|
231
|
+
Initialize.flags = version_control_1.commonFlags;
|
|
232
|
+
Initialize.args = {
|
|
233
|
+
resourceUrl: core_1.Args.string({
|
|
234
|
+
description: "Superblocks resource URL (i.e. https://app.superblocks.com/applications/<application_id>/pages/<page_id>)",
|
|
235
|
+
required: false,
|
|
236
|
+
}),
|
|
237
|
+
};
|
|
238
|
+
exports.default = Initialize;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
export default class Login extends Command {
|
|
3
|
+
static description: string;
|
|
4
|
+
static flags: {
|
|
5
|
+
token: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
|
|
6
|
+
superblocksBaseUrl: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
|
|
7
|
+
};
|
|
8
|
+
run(): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const sdk_1 = require("@superblocksteam/sdk");
|
|
5
|
+
const util_1 = require("@superblocksteam/util");
|
|
6
|
+
const colorette_1 = require("colorette");
|
|
7
|
+
// eslint-disable-next-line unicorn/prefer-module -- enquirer is not ESM
|
|
8
|
+
const { Select } = require("enquirer");
|
|
9
|
+
class Login extends core_1.Command {
|
|
10
|
+
async run() {
|
|
11
|
+
const { flags } = await this.parse(Login);
|
|
12
|
+
let token = flags.token;
|
|
13
|
+
let superblocksBaseUrl = flags.superblocksUrl;
|
|
14
|
+
if (!token) {
|
|
15
|
+
const result = await (0, util_1.getLocalTokenWithUrlIfExists)();
|
|
16
|
+
if (result) {
|
|
17
|
+
({ token, superblocksBaseUrl } = result);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
const customChoice = "Custom (enter your own)";
|
|
21
|
+
const selectPrompt = new Select({
|
|
22
|
+
message: "Select the Superblocks base URL",
|
|
23
|
+
choices: [
|
|
24
|
+
"https://app.superblocks.com/",
|
|
25
|
+
"https://eu.superblocks.com/",
|
|
26
|
+
customChoice,
|
|
27
|
+
],
|
|
28
|
+
});
|
|
29
|
+
superblocksBaseUrl = await selectPrompt.run();
|
|
30
|
+
if (superblocksBaseUrl === customChoice) {
|
|
31
|
+
superblocksBaseUrl = await core_1.ux.prompt("Enter the Superblocks base URL (then press Enter)", { type: "normal" });
|
|
32
|
+
}
|
|
33
|
+
const tokenPageUrl = new URL("personal-settings#profile", superblocksBaseUrl).href;
|
|
34
|
+
token = await core_1.ux.prompt(`Enter your Superblocks access token (then press Enter) which can be found at ${tokenPageUrl}`, { type: "mask" });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
this.log();
|
|
38
|
+
try {
|
|
39
|
+
const sdk = new sdk_1.SuperblocksSdk(token, superblocksBaseUrl);
|
|
40
|
+
const user = await sdk.fetchCurrentUser();
|
|
41
|
+
await (0, util_1.saveApiToken)(token, superblocksBaseUrl);
|
|
42
|
+
this.log((0, colorette_1.green)(`Welcome to the Superblocks 🐨 CLI ${user.name}!`));
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
if (error.name === util_1.ERROR_FILE_ACCESS) {
|
|
46
|
+
this.log((0, colorette_1.red)("Could not save token, ensure the Superblocks CLI has access to create folders in your home directory."));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
this.log((0, colorette_1.red)("Invalid token supplied."));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
Login.description = "Authenticates with Superblocks cloud";
|
|
54
|
+
Login.flags = {
|
|
55
|
+
// flag with a value (-t, --token=VALUE)
|
|
56
|
+
token: core_1.Flags.string({
|
|
57
|
+
char: "t",
|
|
58
|
+
description: "Superblocks user access token",
|
|
59
|
+
}),
|
|
60
|
+
// flag with a value (-b, --superblocksBaseUrl=VALUE)
|
|
61
|
+
superblocksBaseUrl: core_1.Flags.string({
|
|
62
|
+
char: "b",
|
|
63
|
+
description: "Superblocks base URL",
|
|
64
|
+
}),
|
|
65
|
+
};
|
|
66
|
+
exports.default = Login;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AuthenticatedCommand } from "../common/authenticated-command";
|
|
2
|
+
export default class Pull extends AuthenticatedCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
mode: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
|
|
7
|
+
};
|
|
8
|
+
static args: {
|
|
9
|
+
only: import("@oclif/core/lib/interfaces/parser").Arg<string | undefined, Record<string, unknown>>;
|
|
10
|
+
};
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
private createTasks;
|
|
13
|
+
private getResourceIdsToPull;
|
|
14
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
5
|
+
const core_1 = require("@oclif/core");
|
|
6
|
+
const util_1 = require("@superblocksteam/util");
|
|
7
|
+
const fs = tslib_1.__importStar(require("fs-extra"));
|
|
8
|
+
const listr2_1 = require("listr2");
|
|
9
|
+
const authenticated_command_1 = require("../common/authenticated-command");
|
|
10
|
+
const version_control_1 = require("../common/version-control");
|
|
11
|
+
class Pull extends authenticated_command_1.AuthenticatedCommand {
|
|
12
|
+
async run() {
|
|
13
|
+
const { flags, args } = await this.parse(Pull);
|
|
14
|
+
const tasks = this.createTasks(args.only, flags.mode);
|
|
15
|
+
await tasks.run();
|
|
16
|
+
}
|
|
17
|
+
createTasks(only, mode) {
|
|
18
|
+
const tasks = new listr2_1.Listr([
|
|
19
|
+
{
|
|
20
|
+
title: "Checking for existing Superblocks project...",
|
|
21
|
+
task: async (ctx) => {
|
|
22
|
+
ctx.writtenResources = {};
|
|
23
|
+
ctx.now = Date.now();
|
|
24
|
+
try {
|
|
25
|
+
[
|
|
26
|
+
ctx.existingSuperblocksRootConfig,
|
|
27
|
+
ctx.superblocksRootConfigPath,
|
|
28
|
+
] = await (0, util_1.getSuperblocksMonorepoConfigJson)(true);
|
|
29
|
+
ctx.existingSuperblocksResourceConfig =
|
|
30
|
+
await (0, util_1.getSuperblocksResourceConfigIfExists)();
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// no existing superblocks config
|
|
34
|
+
this.error("No Superblocks project found in the current folder hierarchy. Run 'superblocks init' to initialize a new project.");
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
title: "Pulling resources...",
|
|
40
|
+
task: async (ctx, task) => {
|
|
41
|
+
var _a;
|
|
42
|
+
const viewMode = await (0, version_control_1.getMode)(task, mode);
|
|
43
|
+
const resourceIdsToPull = await this.getResourceIdsToPull(ctx, task, only);
|
|
44
|
+
const subtasks = [];
|
|
45
|
+
const now = Date.now();
|
|
46
|
+
const superblocksRootPath = node_path_1.default.resolve(node_path_1.default.dirname(ctx.superblocksRootConfigPath), "..");
|
|
47
|
+
for (const resourceId of resourceIdsToPull) {
|
|
48
|
+
const resource = (_a = ctx.existingSuperblocksRootConfig) === null || _a === void 0 ? void 0 : _a.resources[resourceId];
|
|
49
|
+
switch (resource === null || resource === void 0 ? void 0 : resource.resourceType) {
|
|
50
|
+
case "APPLICATION": {
|
|
51
|
+
subtasks.push({
|
|
52
|
+
title: `Pulling application ${resource.location}...`,
|
|
53
|
+
task: async (_ctx, task) => {
|
|
54
|
+
const application = await this.getSdk().fetchApplication(resourceId, viewMode);
|
|
55
|
+
task.title += `: fetched`;
|
|
56
|
+
ctx.writtenResources[resourceId] =
|
|
57
|
+
await (0, version_control_1.writeResourceToDisk)("APPLICATION", resourceId, application, now, superblocksRootPath, resource.location);
|
|
58
|
+
task.title += `: done`;
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
case "BACKEND": {
|
|
64
|
+
subtasks.push({
|
|
65
|
+
title: `Fetching backend ${resource.location}...`,
|
|
66
|
+
task: async (_ctx, task) => {
|
|
67
|
+
const backend = await this.getSdk().fetchApi(resourceId, viewMode);
|
|
68
|
+
task.title += `: fetched`;
|
|
69
|
+
ctx.writtenResources[resourceId] =
|
|
70
|
+
await (0, version_control_1.writeResourceToDisk)("BACKEND", resourceId, backend, now, superblocksRootPath, resource.location);
|
|
71
|
+
task.title += `: done`;
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
default: {
|
|
77
|
+
this.error(`Unsupported resource type, resource: ${JSON.stringify(resource)}
|
|
78
|
+
`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return task.newListr(subtasks, {
|
|
83
|
+
concurrent: true,
|
|
84
|
+
});
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
title: "Updating Superblocks project file...",
|
|
89
|
+
task: async (ctx) => {
|
|
90
|
+
var _a;
|
|
91
|
+
const superblocksRootConfig = {
|
|
92
|
+
configType: "ROOT",
|
|
93
|
+
resources: ctx.existingSuperblocksRootConfig.resources,
|
|
94
|
+
metadata: {
|
|
95
|
+
...(_a = ctx.existingSuperblocksRootConfig) === null || _a === void 0 ? void 0 : _a.metadata,
|
|
96
|
+
lastUpdated: ctx.now,
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
for (const [resourceId, resource] of Object.entries(ctx.writtenResources)) {
|
|
100
|
+
superblocksRootConfig.resources[resourceId] = resource;
|
|
101
|
+
}
|
|
102
|
+
// update superblocks.json file
|
|
103
|
+
await fs.writeFile(ctx.superblocksRootConfigPath, JSON.stringify((0, version_control_1.sortByKey)(superblocksRootConfig), null, 2));
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
], {
|
|
107
|
+
concurrent: false,
|
|
108
|
+
});
|
|
109
|
+
return tasks;
|
|
110
|
+
}
|
|
111
|
+
async getResourceIdsToPull(ctx, task, only) {
|
|
112
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
113
|
+
if (only) {
|
|
114
|
+
for (const [resourceId, resource] of Object.entries((_b = (_a = ctx.existingSuperblocksRootConfig) === null || _a === void 0 ? void 0 : _a.resources) !== null && _b !== void 0 ? _b : {})) {
|
|
115
|
+
if (resource.location === only) {
|
|
116
|
+
return [resourceId];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const resource = Object.entries((_d = (_c = ctx.existingSuperblocksRootConfig) === null || _c === void 0 ? void 0 : _c.resources) !== null && _d !== void 0 ? _d : {}).find(([, resource]) => resource.location === only);
|
|
120
|
+
if (resource) {
|
|
121
|
+
return [resource[0]];
|
|
122
|
+
}
|
|
123
|
+
throw new Error(`No resource found with the given location: ${only}`);
|
|
124
|
+
}
|
|
125
|
+
const choices = [];
|
|
126
|
+
const initialSelections = [];
|
|
127
|
+
let counter = 0;
|
|
128
|
+
for (const [resourceId, resource] of Object.entries((_f = (_e = ctx.existingSuperblocksRootConfig) === null || _e === void 0 ? void 0 : _e.resources) !== null && _f !== void 0 ? _f : {})) {
|
|
129
|
+
choices.push({
|
|
130
|
+
name: resourceId,
|
|
131
|
+
message: `${resource.location} (Last updated at ${new Date(resource.lastUpdated).toLocaleTimeString()})`,
|
|
132
|
+
});
|
|
133
|
+
if (((_g = ctx.existingSuperblocksResourceConfig) === null || _g === void 0 ? void 0 : _g.id) === resourceId) {
|
|
134
|
+
initialSelections.push(counter);
|
|
135
|
+
}
|
|
136
|
+
counter++;
|
|
137
|
+
}
|
|
138
|
+
const resourceIdsToPull = await task.prompt([
|
|
139
|
+
{
|
|
140
|
+
type: "MultiSelect",
|
|
141
|
+
name: "resourceIdsToPull",
|
|
142
|
+
message: `Select resources to pull (${version_control_1.MULTI_SELECT_PROMPT_HELP})`,
|
|
143
|
+
choices: choices,
|
|
144
|
+
initial: initialSelections,
|
|
145
|
+
validate: version_control_1.atLeastOneSelection,
|
|
146
|
+
prefix: "▸",
|
|
147
|
+
indicator: "◉",
|
|
148
|
+
},
|
|
149
|
+
]);
|
|
150
|
+
return resourceIdsToPull;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
Pull.description = "Download objects from Superblocks and save them locally";
|
|
154
|
+
Pull.examples = [
|
|
155
|
+
"<%= config.bin %> <%= command.id %>",
|
|
156
|
+
"<%= config.bin %> <%= command.id %> apps/my-app",
|
|
157
|
+
"<%= config.bin %> <%= command.id %> backends/my-workflow",
|
|
158
|
+
"<%= config.bin %> <%= command.id %> backends/my-scheduled-job",
|
|
159
|
+
];
|
|
160
|
+
Pull.flags = version_control_1.commonFlags;
|
|
161
|
+
Pull.args = {
|
|
162
|
+
only: core_1.Args.string({
|
|
163
|
+
description: "Superblocks resource location to pull (i.e. apps/my-app or backends/my-workflow)",
|
|
164
|
+
required: false,
|
|
165
|
+
}),
|
|
166
|
+
};
|
|
167
|
+
exports.default = Pull;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Command } from "@oclif/core";
|
|
2
|
+
import { SuperblocksSdk } from "@superblocksteam/sdk";
|
|
3
|
+
import { SuperblocksApplicationConfig } from "@superblocksteam/util";
|
|
4
|
+
export declare abstract class AuthenticatedCommand extends Command {
|
|
5
|
+
private sdk;
|
|
6
|
+
protected init(): Promise<void>;
|
|
7
|
+
protected getBaseUrl(): Promise<string>;
|
|
8
|
+
protected getSdk(): SuperblocksSdk;
|
|
9
|
+
}
|
|
10
|
+
export declare abstract class AuthenticatedApplicationCommand extends AuthenticatedCommand {
|
|
11
|
+
applicationConfig: SuperblocksApplicationConfig;
|
|
12
|
+
protected getEditModeUrl(): Promise<string>;
|
|
13
|
+
protected init(): Promise<void>;
|
|
14
|
+
}
|