@embeddable.com/sdk-core 3.7.2 → 3.7.4

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.
@@ -0,0 +1,2 @@
1
+ export declare function getWorkspaces(ctx: any, token: string, workspaceSpinner: any): Promise<any>;
2
+ export declare function selectWorkspace(ora: any, ctx: any, token: string): Promise<any>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@embeddable.com/sdk-core",
3
- "version": "3.7.2",
3
+ "version": "3.7.4",
4
4
  "description": "Core Embeddable SDK module responsible for web-components bundling and publishing.",
5
5
  "keywords": [
6
6
  "embeddable",
package/src/dev.ts CHANGED
@@ -24,6 +24,7 @@ import { archive, YAML_OR_JS_FILES, sendBuild } from "./push";
24
24
  import validate from "./validate";
25
25
  import { checkNodeVersion } from "./utils";
26
26
  import { createManifest } from "./cleanup";
27
+ import { selectWorkspace } from "./workspaceUtils";
27
28
  const minimist = require("minimist");
28
29
 
29
30
  const oraP = import("ora");
@@ -99,7 +100,7 @@ export default async () => {
99
100
  const workspacePreparation = ora("Preparing workspace...").start();
100
101
 
101
102
  try {
102
- previewWorkspace = await getPreviewWorkspace(config);
103
+ previewWorkspace = await getPreviewWorkspace(workspacePreparation, config);
103
104
  } catch (e: any) {
104
105
  workspacePreparation.fail(e.response.data?.errorMessage);
105
106
  process.exit(1);
@@ -320,11 +321,21 @@ const onClose = async (
320
321
  process.exit(0);
321
322
  };
322
323
 
323
- const getPreviewWorkspace = async (ctx: any): Promise<string> => {
324
+ const getPreviewWorkspace = async (
325
+ startedOra: any,
326
+ ctx: any,
327
+ ): Promise<string> => {
324
328
  const token = await getToken();
325
329
 
326
330
  const params = minimist(process.argv.slice(2));
327
- const primaryWorkspace = params.w || params.workspace;
331
+ let primaryWorkspace = params.w || params.workspace;
332
+
333
+ if (!primaryWorkspace) {
334
+ startedOra.stop(); // Stop current Ora, otherwise the last option will get hidden by it.
335
+ const { workspaceId } = await selectWorkspace(ora, ctx, token);
336
+ primaryWorkspace = workspaceId;
337
+ startedOra.start();
338
+ }
328
339
 
329
340
  try {
330
341
  const response = await axios.get(
@@ -341,7 +352,7 @@ const getPreviewWorkspace = async (ctx: any): Promise<string> => {
341
352
  if (e.response.status === 401) {
342
353
  // login and retry
343
354
  await login();
344
- return await getPreviewWorkspace(ctx);
355
+ return await getPreviewWorkspace(startedOra, ctx);
345
356
  } else {
346
357
  throw e;
347
358
  }
package/src/push.ts CHANGED
@@ -3,7 +3,7 @@ import * as fsSync from "node:fs";
3
3
  import * as archiver from "archiver";
4
4
  import axios from "axios";
5
5
  const oraP = import("ora");
6
- const inquirerSelect = import("@inquirer/select");
6
+
7
7
  import provideConfig from "./provideConfig";
8
8
  // @ts-ignore
9
9
  import reportErrorToRollbar from "./rollbar.mjs";
@@ -11,6 +11,7 @@ import reportErrorToRollbar from "./rollbar.mjs";
11
11
  import { findFiles } from "@embeddable.com/sdk-utils";
12
12
  import { getToken } from "./login";
13
13
  import { checkBuildSuccess, checkNodeVersion, getArgumentByKey } from "./utils";
14
+ import { selectWorkspace } from "./workspaceUtils";
14
15
 
15
16
  // grab .cube.yml|js and .sc.yml|js files
16
17
  export const YAML_OR_JS_FILES = /^(.*)\.(cube|sc)\.(ya?ml|js)$/;
@@ -53,6 +54,7 @@ export default async () => {
53
54
  .info("No API Key provided. Standard login will be used.");
54
55
 
55
56
  const { workspaceId, name: workspaceName } = await selectWorkspace(
57
+ ora,
56
58
  config,
57
59
  token,
58
60
  );
@@ -110,44 +112,6 @@ async function pushByApiKey(config: any, spinner: any) {
110
112
  });
111
113
  }
112
114
 
113
- async function selectWorkspace(ctx: any, token: string) {
114
- const workspaceSpinner = ora({
115
- text: `Fetching workspaces using ${ctx.pushBaseUrl}...`,
116
- color: "green",
117
- discardStdin: false,
118
- }).start();
119
-
120
- const availableWorkspaces = await getWorkspaces(ctx, token, workspaceSpinner);
121
-
122
- let selectedWorkspace;
123
-
124
- if (availableWorkspaces.length === 0) {
125
- workspaceSpinner.fail("No workspaces found");
126
- process.exit(1);
127
- }
128
-
129
- workspaceSpinner.info(`Found ${availableWorkspaces.length} workspace(s)`);
130
-
131
- if (availableWorkspaces.length === 1) {
132
- selectedWorkspace = availableWorkspaces[0];
133
- } else {
134
- const select = (await inquirerSelect).default;
135
- selectedWorkspace = await select({
136
- message: "Select workspace to push changes",
137
- choices: availableWorkspaces.map((workspace: any) => ({
138
- name: `${workspace.name} (${workspace.workspaceId})`,
139
- value: workspace,
140
- })),
141
- });
142
- }
143
-
144
- workspaceSpinner.succeed(
145
- `Workspace: ${selectedWorkspace.name} (${selectedWorkspace.workspaceId})`,
146
- );
147
-
148
- return selectedWorkspace;
149
- }
150
-
151
115
  async function verify(ctx: any) {
152
116
  try {
153
117
  await fs.access(ctx.client.buildDir);
@@ -297,24 +261,3 @@ async function uploadFile(formData: any, url: string, token: string) {
297
261
  maxBodyLength: Infinity,
298
262
  });
299
263
  }
300
-
301
- async function getWorkspaces(ctx: any, token: string, workspaceSpinner: any) {
302
- try {
303
- const response = await axios.get(`${ctx.pushBaseUrl}/workspace`, {
304
- headers: {
305
- Authorization: `Bearer ${token}`,
306
- },
307
- });
308
-
309
- return response.data?.filter((w: any) => !w.devWorkspace);
310
- } catch (e: any) {
311
- if (e.response.status === 401) {
312
- workspaceSpinner.fail(
313
- 'Unauthorized. Please login using "embeddable login" command.',
314
- );
315
- } else {
316
- workspaceSpinner.fail("Failed to fetch workspaces");
317
- }
318
- process.exit(1);
319
- }
320
- }
package/src/utils.test.ts CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  const startMock = {
11
11
  succeed: vi.fn(),
12
12
  fail: vi.fn(),
13
+ stop: vi.fn(),
13
14
  };
14
15
 
15
16
  const failMock = vi.fn();
@@ -58,11 +59,9 @@ describe("utils", () => {
58
59
  vi.spyOn(process, "exit").mockImplementation(() => null as never);
59
60
 
60
61
  const result = await checkNodeVersion();
61
-
62
- expect(failMock).toHaveBeenCalledWith({
63
- text: "Node version 16.0 or higher is required. You are running 14.0.",
64
- color: "red",
65
- });
62
+ expect(startMock.fail).toHaveBeenCalledWith(
63
+ "Node version 16.0 or higher is required. You are running 14.0.",
64
+ );
66
65
 
67
66
  expect(result).toBe(undefined);
68
67
  });
package/src/utils.ts CHANGED
@@ -3,10 +3,9 @@ import * as fs from "node:fs/promises";
3
3
  import { CREDENTIALS_DIR } from "./credentials";
4
4
  import path from "node:path";
5
5
 
6
- let ora: any;
7
6
  export const checkNodeVersion = async () => {
8
- ora = (await oraP).default;
9
- const spinner = ora("Checking node version...");
7
+ const ora = (await oraP).default;
8
+ const spinner = ora("Checking node version...").start();
10
9
  const [major, minor] = process.versions.node.split(".").map(Number);
11
10
 
12
11
  const packageJson = await import("../package.json");
@@ -20,13 +19,13 @@ export const checkNodeVersion = async () => {
20
19
  .map(Number);
21
20
 
22
21
  if (major < minMajor || (major === minMajor && minor < minMinor)) {
23
- spinner.fail({
24
- text: `Node version ${minMajor}.${minMinor} or higher is required. You are running ${major}.${minor}.`,
25
- color: "red",
26
- });
22
+ spinner.fail(
23
+ `Node version ${minMajor}.${minMinor} or higher is required. You are running ${major}.${minor}.`,
24
+ );
27
25
 
28
26
  process.exit(1);
29
27
  } else {
28
+ spinner.stop();
30
29
  return true;
31
30
  }
32
31
  };
@@ -0,0 +1,131 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import axios from "axios";
3
+ import { getWorkspaces, selectWorkspace } from "./workspaceUtils";
4
+ const inquirerSelect = import("@inquirer/select");
5
+
6
+ vi.mock("axios");
7
+
8
+ vi.mock("@inquirer/select", () => ({
9
+ default: vi.fn(),
10
+ }));
11
+
12
+ describe("workspaceUtils", () => {
13
+ describe("getWorkspaces", () => {
14
+ it("should fetch workspaces and filter out dev workspaces", async () => {
15
+ const ctx = { pushBaseUrl: "http://example.com" };
16
+ const token = "test-token";
17
+ const workspaceSpinner = { fail: vi.fn() };
18
+
19
+ const workspaces = [
20
+ { name: "Workspace 1", workspaceId: "1", devWorkspace: false },
21
+ { name: "Workspace 2", workspaceId: "2", devWorkspace: true },
22
+ ];
23
+
24
+ (axios.get as any).mockResolvedValue({ data: workspaces });
25
+
26
+ const result = await getWorkspaces(ctx, token, workspaceSpinner);
27
+
28
+ expect(result).toEqual([
29
+ { name: "Workspace 1", workspaceId: "1", devWorkspace: false },
30
+ ]);
31
+ });
32
+
33
+ it("should handle unauthorized error", async () => {
34
+ const ctx = { pushBaseUrl: "http://example.com" };
35
+ const token = "test-token";
36
+ const workspaceSpinner = { fail: vi.fn() };
37
+
38
+ (axios.get as any).mockRejectedValue({ response: { status: 401 } });
39
+
40
+ await expect(
41
+ getWorkspaces(ctx, token, workspaceSpinner),
42
+ ).rejects.toThrow();
43
+ expect(workspaceSpinner.fail).toHaveBeenCalledWith(
44
+ 'Unauthorized. Please login using "embeddable login" command.',
45
+ );
46
+ });
47
+
48
+ it("should handle other errors", async () => {
49
+ const ctx = { pushBaseUrl: "http://example.com" };
50
+ const token = "test-token";
51
+ const workspaceSpinner = { fail: vi.fn() };
52
+
53
+ (axios.get as any).mockRejectedValue({ response: { status: 500 } });
54
+
55
+ await expect(
56
+ getWorkspaces(ctx, token, workspaceSpinner),
57
+ ).rejects.toThrow();
58
+ expect(workspaceSpinner.fail).toHaveBeenCalledWith(
59
+ "Failed to fetch workspaces",
60
+ );
61
+ });
62
+ });
63
+
64
+ describe("selectWorkspace", () => {
65
+ it("should select a workspace when only one is available", async () => {
66
+ const ora = vi.fn().mockReturnValue({
67
+ start: vi.fn().mockReturnThis(),
68
+ fail: vi.fn(),
69
+ info: vi.fn(),
70
+ succeed: vi.fn(),
71
+ });
72
+
73
+ const ctx = { pushBaseUrl: "http://example.com" };
74
+ const token = "test-token";
75
+
76
+ const workspaces = [
77
+ { name: "Workspace 1", workspaceId: "1", devWorkspace: false },
78
+ ];
79
+
80
+ (axios.get as any).mockResolvedValue({ data: workspaces });
81
+
82
+ const selectedWorkspace = await selectWorkspace(ora, ctx, token);
83
+
84
+ expect(selectedWorkspace).toEqual(workspaces[0]);
85
+ expect(ora().succeed).toHaveBeenCalledWith(`Workspace: Workspace 1 (1)`);
86
+ });
87
+
88
+ it("should prompt user to select a workspace when multiple are available", async () => {
89
+ const ora = vi.fn().mockReturnValue({
90
+ start: vi.fn().mockReturnThis(),
91
+ fail: vi.fn(),
92
+ info: vi.fn(),
93
+ succeed: vi.fn(),
94
+ });
95
+ const ctx = { pushBaseUrl: "http://example.com" };
96
+ const token = "test-token";
97
+
98
+ const workspaces = [
99
+ { name: "Workspace 1", workspaceId: "1", devWorkspace: false },
100
+ { name: "Workspace 2", workspaceId: "2", devWorkspace: false },
101
+ ];
102
+
103
+ (axios.get as any).mockResolvedValue({ data: workspaces });
104
+
105
+ vi.mocked((await inquirerSelect).default).mockResolvedValue(
106
+ workspaces[1],
107
+ );
108
+
109
+ const selectedWorkspace = await selectWorkspace(ora, ctx, token);
110
+
111
+ expect(selectedWorkspace).toEqual(workspaces[1]);
112
+ expect(ora().succeed).toHaveBeenCalledWith(`Workspace: Workspace 2 (2)`);
113
+ });
114
+
115
+ it("should handle no workspaces found", async () => {
116
+ const ora = vi.fn().mockReturnValue({
117
+ start: vi.fn().mockReturnThis(),
118
+ fail: vi.fn(),
119
+ info: vi.fn(),
120
+ succeed: vi.fn(),
121
+ });
122
+ const ctx = { pushBaseUrl: "http://example.com" };
123
+ const token = "test-token";
124
+
125
+ (axios.get as any).mockResolvedValue({ data: [] });
126
+
127
+ await expect(selectWorkspace(ora, ctx, token)).rejects.toThrow();
128
+ expect(ora().fail).toHaveBeenCalledWith("No workspaces found");
129
+ });
130
+ });
131
+ });
@@ -0,0 +1,65 @@
1
+ const inquirerSelect = import("@inquirer/select");
2
+ import axios from "axios";
3
+
4
+ export async function getWorkspaces(
5
+ ctx: any,
6
+ token: string,
7
+ workspaceSpinner: any,
8
+ ) {
9
+ try {
10
+ const response = await axios.get(`${ctx.pushBaseUrl}/workspace`, {
11
+ headers: {
12
+ Authorization: `Bearer ${token}`,
13
+ },
14
+ });
15
+
16
+ return response.data?.filter((w: any) => !w.devWorkspace);
17
+ } catch (e: any) {
18
+ if (e.response.status === 401) {
19
+ workspaceSpinner.fail(
20
+ 'Unauthorized. Please login using "embeddable login" command.',
21
+ );
22
+ } else {
23
+ workspaceSpinner.fail("Failed to fetch workspaces");
24
+ }
25
+ process.exit(1);
26
+ }
27
+ }
28
+
29
+ export async function selectWorkspace(ora: any, ctx: any, token: string) {
30
+ const workspaceSpinner = ora({
31
+ text: `Fetching workspaces using ${ctx.pushBaseUrl}...`,
32
+ color: "green",
33
+ discardStdin: false,
34
+ }).start();
35
+
36
+ const availableWorkspaces = await getWorkspaces(ctx, token, workspaceSpinner);
37
+
38
+ let selectedWorkspace;
39
+
40
+ if (availableWorkspaces.length === 0) {
41
+ workspaceSpinner.fail("No workspaces found");
42
+ process.exit(1);
43
+ }
44
+
45
+ workspaceSpinner.info(`Found ${availableWorkspaces.length} workspace(s)`);
46
+
47
+ if (availableWorkspaces.length === 1) {
48
+ selectedWorkspace = availableWorkspaces[0];
49
+ } else {
50
+ const select = (await inquirerSelect).default;
51
+ selectedWorkspace = await select({
52
+ message: "Select workspace to push changes",
53
+ choices: availableWorkspaces.map((workspace: any) => ({
54
+ name: `${workspace.name} (${workspace.workspaceId})`,
55
+ value: workspace,
56
+ })),
57
+ });
58
+ }
59
+
60
+ workspaceSpinner.succeed(
61
+ `Workspace: ${selectedWorkspace.name} (${selectedWorkspace.workspaceId})`,
62
+ );
63
+
64
+ return selectedWorkspace;
65
+ }