@embeddable.com/sdk-core 4.1.9 → 4.1.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@embeddable.com/sdk-core",
3
- "version": "4.1.9",
3
+ "version": "4.1.10",
4
4
  "description": "Core Embeddable SDK module responsible for web-components bundling and publishing.",
5
5
  "keywords": [
6
6
  "embeddable",
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "license": "MIT",
42
42
  "dependencies": {
43
- "@embeddable.com/core": "2.13.5",
43
+ "@embeddable.com/core": "2.13.6",
44
44
  "@embeddable.com/sdk-utils": "0.9.0",
45
45
  "@inquirer/prompts": "^7.2.1",
46
46
  "@stencil/core": "^4.23.0",
package/src/dev.test.ts CHANGED
@@ -48,7 +48,11 @@ vi.mock("@stencil/core/sys/node", () => ({
48
48
  createNodeSys: vi.fn(),
49
49
  }));
50
50
  vi.mock("open", () => ({ default: vi.fn() }));
51
- vi.mock("ws", () => ({ WebSocketServer: vi.fn() }));
51
+ vi.mock("ws", () => ({
52
+ WebSocketServer: class WebSocketServer {
53
+ constructor() {}
54
+ }
55
+ }));
52
56
  vi.mock("chokidar", () => ({ watch: vi.fn((_) => ({ on: vi.fn() })) }));
53
57
  vi.mock("./login", () => ({ getToken: vi.fn(), default: vi.fn() }));
54
58
  vi.mock("axios", () => ({ default: { get: vi.fn(), post: vi.fn() } }));
@@ -135,7 +139,7 @@ describe("dev command", () => {
135
139
  let oraMock: any;
136
140
  let mockServer: any;
137
141
 
138
- beforeEach(() => {
142
+ beforeEach(async () => {
139
143
  listenMock = vi.fn();
140
144
  wsMock = {
141
145
  send: vi.fn(),
@@ -155,12 +159,14 @@ describe("dev command", () => {
155
159
  };
156
160
 
157
161
  vi.mocked(http.createServer).mockImplementation(() => mockServer as any);
158
- vi.mocked(WebSocketServer).mockImplementation(() => {
162
+ // Mock WebSocketServer constructor to return our mock instance
163
+ const wsModule = await import("ws");
164
+ vi.spyOn(wsModule, "WebSocketServer").mockImplementation(function() {
159
165
  return {
160
166
  clients: [wsMock],
161
167
  on: vi.fn(),
162
168
  } as any;
163
- });
169
+ } as any);
164
170
 
165
171
  vi.mocked(ora).mockImplementation(() => oraMock);
166
172
 
@@ -398,7 +404,10 @@ describe("dev command", () => {
398
404
  on: vi.fn(),
399
405
  close: vi.fn(),
400
406
  };
401
- vi.mocked(WebSocketServer).mockImplementation(() => mockWss as any);
407
+ const wsModule = await import("ws");
408
+ vi.spyOn(wsModule, "WebSocketServer").mockImplementation(function() {
409
+ return mockWss as any;
410
+ } as any);
402
411
  vi.mocked(validate).mockResolvedValue(true);
403
412
  const error = new Error("Archive failed");
404
413
  vi.mocked(archive).mockRejectedValue(error);
@@ -1002,7 +1011,10 @@ describe("dev command", () => {
1002
1011
  close: vi.fn(),
1003
1012
  };
1004
1013
 
1005
- vi.mocked(WebSocketServer).mockImplementation(() => mockWss as any);
1014
+ const wsModule = await import("ws");
1015
+ vi.spyOn(wsModule, "WebSocketServer").mockImplementation(function() {
1016
+ return mockWss as any;
1017
+ } as any);
1006
1018
 
1007
1019
  await dev();
1008
1020
 
@@ -1040,7 +1052,10 @@ describe("dev command", () => {
1040
1052
  close: vi.fn(),
1041
1053
  };
1042
1054
 
1043
- vi.mocked(WebSocketServer).mockImplementation(() => mockWss as any);
1055
+ const wsModule = await import("ws");
1056
+ vi.spyOn(wsModule, "WebSocketServer").mockImplementation(function() {
1057
+ return mockWss as any;
1058
+ } as any);
1044
1059
 
1045
1060
  await dev();
1046
1061
 
@@ -1100,7 +1115,10 @@ describe("dev command", () => {
1100
1115
  close: vi.fn(),
1101
1116
  };
1102
1117
 
1103
- vi.mocked(WebSocketServer).mockImplementation(() => mockWss as any);
1118
+ const wsModule = await import("ws");
1119
+ vi.spyOn(wsModule, "WebSocketServer").mockImplementation(function() {
1120
+ return mockWss as any;
1121
+ } as any);
1104
1122
  vi.mocked(validate).mockResolvedValue(false);
1105
1123
 
1106
1124
  await dev();
@@ -1268,7 +1286,10 @@ describe("dev command", () => {
1268
1286
  close: vi.fn(),
1269
1287
  };
1270
1288
 
1271
- vi.mocked(WebSocketServer).mockImplementation(() => mockWss as any);
1289
+ const wsModule = await import("ws");
1290
+ vi.spyOn(wsModule, "WebSocketServer").mockImplementation(function() {
1291
+ return mockWss as any;
1292
+ } as any);
1272
1293
 
1273
1294
  await dev();
1274
1295
 
@@ -1404,7 +1425,10 @@ describe("dev command", () => {
1404
1425
  close: vi.fn(),
1405
1426
  };
1406
1427
 
1407
- vi.mocked(WebSocketServer).mockImplementation(() => mockWss as any);
1428
+ const wsModule = await import("ws");
1429
+ vi.spyOn(wsModule, "WebSocketServer").mockImplementation(function() {
1430
+ return mockWss as any;
1431
+ } as any);
1408
1432
 
1409
1433
  await dev();
1410
1434
 
@@ -1456,7 +1480,10 @@ describe("dev command", () => {
1456
1480
  close: vi.fn(),
1457
1481
  };
1458
1482
 
1459
- vi.mocked(WebSocketServer).mockImplementation(() => mockWss as any);
1483
+ const wsModule = await import("ws");
1484
+ vi.spyOn(wsModule, "WebSocketServer").mockImplementation(function() {
1485
+ return mockWss as any;
1486
+ } as any);
1460
1487
 
1461
1488
  vi.mocked(provideConfig).mockResolvedValue({
1462
1489
  ...mockConfig,
@@ -1569,12 +1596,14 @@ describe("dev command", () => {
1569
1596
  };
1570
1597
 
1571
1598
  // Make sure WebSocketServer returns undefined clients
1572
- vi.mocked(WebSocketServer).mockImplementation(
1573
- () =>
1574
- ({
1599
+ const wsModule = await import("ws");
1600
+ vi.spyOn(wsModule, "WebSocketServer").mockImplementation(
1601
+ function() {
1602
+ return {
1575
1603
  clients: undefined,
1576
1604
  close: vi.fn(),
1577
- }) as any,
1605
+ } as any;
1606
+ } as any,
1578
1607
  );
1579
1608
 
1580
1609
  await configureWatcher(mockWatcher as any, mockConfig as any);
package/src/login.test.ts CHANGED
@@ -1,9 +1,5 @@
1
1
  import { server } from "./../../../mocks/server";
2
- import login, { resolveFiles, getToken } from "./login";
3
2
  import { vi } from "vitest";
4
- import { pathToFileURL } from "node:url";
5
- import { existsSync } from "node:fs";
6
- import { PathLike } from "node:fs";
7
3
  import { mkdir, access, writeFile, readFile } from "fs/promises";
8
4
  import { CREDENTIALS_DIR, CREDENTIALS_FILE } from "./credentials";
9
5
  import { http, HttpResponse } from "msw";
@@ -45,25 +41,30 @@ vi.mock("node:fs", () => ({
45
41
  existsSync: vi.fn(),
46
42
  }));
47
43
 
48
- vi.mock("node:url", () => ({
49
- pathToFileURL: vi.fn(),
50
- }));
51
-
52
- // Create a mock module factory
53
- const mockConfigModule = {
54
- default: {
44
+ // Mock provideConfig directly to avoid file:// URL mocking issues
45
+ vi.mock("./provideConfig", () => ({
46
+ default: vi.fn().mockResolvedValue({
55
47
  authDomain: "test-domain.com",
56
- },
57
- };
48
+ authClientId: "test-client-id",
49
+ audienceUrl: "test-audience-url",
50
+ }),
51
+ }));
58
52
 
59
- // Mock both possible config paths
60
- vi.mock(`${process.cwd()}/embeddable.config.js`, () => mockConfigModule);
61
- vi.mock(`${process.cwd()}/embeddable.config.ts`, () => mockConfigModule);
53
+ // Import after mocks are set up
54
+ import login, { resolveFiles, getToken } from "./login";
62
55
 
63
56
  describe("login", () => {
64
57
  beforeEach(async () => {
65
58
  vi.resetModules();
66
59
 
60
+ // Re-mock provideConfig after resetModules
61
+ const provideConfigModule = await import("./provideConfig");
62
+ vi.mocked(provideConfigModule.default).mockResolvedValue({
63
+ authDomain: "test-domain.com",
64
+ authClientId: "test-client-id",
65
+ audienceUrl: "test-audience-url",
66
+ } as any);
67
+
67
68
  vi.mocked(readFile).mockImplementation(async () =>
68
69
  Buffer.from(`{"access_token":"mocked-token"}`),
69
70
  );
@@ -75,16 +76,6 @@ describe("login", () => {
75
76
  vi.mocked(mkdir).mockImplementation(async () => "mocked");
76
77
 
77
78
  vi.mocked(writeFile).mockImplementation(async () => undefined);
78
-
79
- // Mock that only the TS config exists
80
- vi.mocked(existsSync).mockImplementation((path: PathLike) =>
81
- path.toString().endsWith("embeddable.config.ts"),
82
- );
83
-
84
- // Mock URL creation
85
- vi.mocked(pathToFileURL).mockImplementation(
86
- (path) => new URL(`file://${path}`),
87
- );
88
79
  });
89
80
 
90
81
  vi.mock("./reportErrorToRollbar", () => vi.fn());
@@ -1,43 +1,60 @@
1
- import { pathToFileURL } from "node:url";
2
- import { existsSync } from "node:fs";
1
+ import { existsSync, writeFileSync, unlinkSync } from "node:fs";
3
2
  import { PathLike } from "node:fs";
4
- import provideConfig from "./provideConfig";
5
3
  import { vi } from "vitest";
4
+ import { join } from "node:path";
6
5
 
7
- // Mock fs module
8
- vi.mock("node:fs", () => ({
9
- existsSync: vi.fn(),
10
- }));
11
-
12
- // Mock url module
13
- vi.mock("node:url", () => ({
14
- pathToFileURL: vi.fn(),
15
- }));
16
-
17
- // Create a mock module factory
18
- const mockConfigModule = {
19
- default: "mocked-config",
20
- };
21
-
22
- // Mock both possible config paths
23
- vi.mock(`${process.cwd()}/embeddable.config.js`, () => mockConfigModule);
24
- vi.mock(`${process.cwd()}/embeddable.config.ts`, () => mockConfigModule);
6
+ // Mock fs module for existsSync (but allow real writeFileSync/unlinkSync for temp file)
7
+ vi.mock("node:fs", async () => {
8
+ const actual = await vi.importActual<typeof import("node:fs")>("node:fs");
9
+ return {
10
+ ...actual,
11
+ existsSync: vi.fn(),
12
+ };
13
+ });
25
14
 
26
15
  describe("provideConfig", () => {
16
+ const configPath = join(process.cwd(), "embeddable.config.ts");
17
+ const mockConfig = { default: "mocked-config" };
18
+
27
19
  beforeEach(() => {
28
- vi.resetModules();
29
20
  // Mock that only the TS config exists
30
21
  vi.mocked(existsSync).mockImplementation((path: PathLike) =>
31
22
  path.toString().endsWith("embeddable.config.ts"),
32
23
  );
33
- // Mock URL creation
34
- vi.mocked(pathToFileURL).mockImplementation(
35
- (path) => new URL(`file://${path}`),
36
- );
24
+ });
25
+
26
+ afterEach(() => {
27
+ // Clean up temp file if it exists
28
+ try {
29
+ if (existsSync(configPath)) {
30
+ unlinkSync(configPath);
31
+ }
32
+ } catch {
33
+ // Ignore cleanup errors
34
+ }
37
35
  });
38
36
 
39
37
  it("should return the default config when the config file exists", async () => {
38
+ vi.resetModules();
39
+
40
+ // Create a temporary actual config file (more reliable than mocking file:// URLs on Windows)
41
+ writeFileSync(
42
+ configPath,
43
+ `export default ${JSON.stringify(mockConfig.default)};`,
44
+ "utf-8",
45
+ );
46
+
47
+ // Re-mock fs.existsSync after resetModules
48
+ vi.mocked(existsSync).mockImplementation((path: PathLike) =>
49
+ path.toString().endsWith("embeddable.config.ts"),
50
+ );
51
+
52
+ // Dynamically import provideConfig after file is created
53
+ const { default: provideConfig } = await import("./provideConfig");
40
54
  const result = await provideConfig();
41
55
  expect(result).toEqual("mocked-config");
56
+
57
+ // Clean up
58
+ unlinkSync(configPath);
42
59
  });
43
60
  });
package/src/push.test.ts CHANGED
@@ -377,7 +377,7 @@ describe("push", () => {
377
377
  await push();
378
378
 
379
379
  expect(console.error).toHaveBeenCalledWith(
380
- "Expired token. Please login again."
380
+ 'Unauthorized. Please login using "npm run embeddable:login"'
381
381
  );
382
382
  expect(process.exit).toHaveBeenCalledWith(1);
383
383
  });
package/src/push.ts CHANGED
@@ -160,7 +160,7 @@ async function verify(ctx: ResolvedEmbeddableConfig) {
160
160
  const token = await getToken();
161
161
 
162
162
  if (!token) {
163
- console.error("Expired token. Please login again.");
163
+ console.error('Unauthorized. Please login using "npm run embeddable:login"');
164
164
  process.exit(1);
165
165
  }
166
166
 
@@ -35,11 +35,6 @@ vi.mock("node:path", async () => {
35
35
  };
36
36
  });
37
37
 
38
- // mock rollback constructor
39
- vi.mock("rollbar", () => ({
40
- default: vi.fn(),
41
- }));
42
-
43
38
  vi.mock("resolvedPath", () => ({
44
39
  default: vi.fn(),
45
40
  devDependencies: {
@@ -51,28 +46,48 @@ vi.mock("resolvedPath", () => ({
51
46
  },
52
47
  }));
53
48
 
54
- const rollbarInstanceMock = {
55
- error: vi.fn(),
56
- configure: vi.fn(),
57
- };
49
+ // Mock rollbar - define everything inside factory to avoid hoisting issues
50
+ vi.mock("rollbar", () => {
51
+ const mockInstance = {
52
+ error: vi.fn(),
53
+ configure: vi.fn(),
54
+ };
55
+ // Store on globalThis so tests can access it
56
+ (globalThis as any).__rollbarMockInstance = mockInstance;
57
+
58
+ // Return a constructor function that returns the same instance
59
+ function RollbarMock() {
60
+ return mockInstance;
61
+ }
62
+
63
+ return {
64
+ default: RollbarMock,
65
+ };
66
+ });
58
67
 
59
68
  describe("rollbar", () => {
69
+ let rollbarInstance: any;
70
+
60
71
  beforeEach(() => {
61
72
  vi.mocked(provideConfig).mockResolvedValue(
62
73
  config as ResolvedEmbeddableConfig,
63
74
  );
64
- vi.mocked(Rollbar).mockReturnValue(rollbarInstanceMock as any);
65
75
  vi.mocked(path.resolve).mockReturnValue("resolvedPath");
66
76
 
67
77
  vi.mocked(fs.readFile).mockResolvedValue("{}");
68
78
  vi.mocked(jwtDecode).mockReturnValue({ sub: "test", iss: "iss" });
79
+
80
+ // Get the mock instance that will be returned by constructor
81
+ rollbarInstance = (globalThis as any).__rollbarMockInstance;
82
+ rollbarInstance.error.mockClear();
83
+ rollbarInstance.configure.mockClear();
69
84
  });
70
85
 
71
86
  it("should call Rollbar.error with the error", async () => {
72
87
  const error = new Error("test error");
73
88
  await reportErrorToRollbar(error);
74
89
 
75
- expect(rollbarInstanceMock.configure).toHaveBeenCalledWith({
90
+ expect(rollbarInstance.configure).toHaveBeenCalledWith({
76
91
  payload: {
77
92
  person: {
78
93
  id: "iss@test",
@@ -80,7 +95,7 @@ describe("rollbar", () => {
80
95
  },
81
96
  });
82
97
 
83
- expect(rollbarInstanceMock.error).toHaveBeenCalledWith(error, {
98
+ expect(rollbarInstance.error).toHaveBeenCalledWith(error, {
84
99
  custom: {
85
100
  code_version: '{"core":"1.0.0","sdk_core":"1.2.3"}',
86
101
  },
@@ -46,7 +46,7 @@ describe("workspaceUtils", () => {
46
46
  getWorkspaces(ctx as ResolvedEmbeddableConfig, token, workspaceSpinner),
47
47
  ).rejects.toThrow();
48
48
  expect(workspaceSpinner.fail).toHaveBeenCalledWith(
49
- 'Unauthorized. Please login using "embeddable login" command.',
49
+ 'Unauthorized. Please login using "npm run embeddable:login"',
50
50
  );
51
51
  });
52
52
 
@@ -23,7 +23,7 @@ export async function getWorkspaces(
23
23
  }
24
24
  if (e.response?.status === 401) {
25
25
  workspaceSpinner.fail(
26
- 'Unauthorized. Please login using "embeddable login" command.',
26
+ 'Unauthorized. Please login using "npm run embeddable:login"',
27
27
  );
28
28
  } else {
29
29
  workspaceSpinner.fail("Failed to fetch workspaces");
@@ -30,6 +30,7 @@ export class EmbeddableComponent {
30
30
 
31
31
  @Watch('theme')
32
32
  watchTheme() {
33
+ if (!this.rootElement) return;
33
34
  const eventClientContext = new CustomEvent('embeddable-event:update-theme', {
34
35
  bubbles: false,
35
36
  detail: this.theme,
@@ -106,10 +107,11 @@ export class EmbeddableComponent {
106
107
  }
107
108
 
108
109
  private handlePops() {
110
+ const props = JSON.parse(this.props);
109
111
  render(
110
112
  this.rootElement,
111
113
  this.componentName,
112
- JSON.parse(this.props),
114
+ props,
113
115
  JSON.parse(this.clientContext),
114
116
  this.theme
115
117
  );