@embeddable.com/sdk-core 3.4.1 → 3.5.0

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": "3.4.1",
3
+ "version": "3.5.0",
4
4
  "description": "Core Embeddable SDK module responsible for web-components bundling and publishing.",
5
5
  "keywords": [
6
6
  "embeddable",
package/src/cleanup.ts CHANGED
@@ -68,6 +68,7 @@ export async function createManifest({
68
68
  metadata: {
69
69
  nodeVersion: process.version,
70
70
  platform: process.platform,
71
+ bundleHash: ctx.client.bundleHash,
71
72
  sdkVersions,
72
73
  packageManager,
73
74
  packageManagerVersion,
@@ -77,6 +77,7 @@ export default ({
77
77
  errorFallbackComponent: errorFallbackComponent
78
78
  ? path.resolve(clientRoot, errorFallbackComponent)
79
79
  : undefined,
80
+ bundleHash: undefined, // This will be set by the build process
80
81
  },
81
82
  outputOptions: {
82
83
  typesEntryPointFilename: "embeddable-types-entry-point.js",
@@ -0,0 +1,77 @@
1
+ import defineConfig from "./defineConfig";
2
+ import * as path from "node:path";
3
+ import { existsSync } from "node:fs";
4
+
5
+ vi.mock("node:path", async () => {
6
+ const actual = await vi.importActual("node:path");
7
+ return {
8
+ ...actual,
9
+ resolve: vi.fn(),
10
+ };
11
+ });
12
+
13
+ vi.mock("node:fs", () => ({
14
+ existsSync: vi.fn(),
15
+ }));
16
+
17
+ const baseConfigArgs = {
18
+ plugins: [],
19
+ pushBaseUrl: "pushBaseUrl",
20
+ audienceUrl: "audienceUrl",
21
+ authDomain: "authDomain",
22
+ authClientId: "authClientId",
23
+ errorFallbackComponent: "errorFallbackComponent",
24
+ applicationEnvironment: "applicationEnvironment",
25
+ rollbarAccessToken: "rollbarAccessToken",
26
+ previewBaseUrl: "previewBaseUrl",
27
+ modelsSrc: "modelsSrc",
28
+ };
29
+
30
+ describe("defineConfig", () => {
31
+ beforeEach(() => {
32
+ vi.mocked(existsSync).mockReturnValue(true);
33
+ const coreRoot = "/embeddable-sdk/packages/core-sdk";
34
+ vi.mocked(path.resolve).mockReturnValue(coreRoot);
35
+
36
+ vi.spyOn(process, "cwd").mockReturnValue(
37
+ "/embeddable-sdk/packages/core-sdk",
38
+ );
39
+ });
40
+
41
+ it("should return a config object", async () => {
42
+ const config = await defineConfig(baseConfigArgs);
43
+
44
+ expect(config).toMatchInlineSnapshot(`
45
+ {
46
+ "applicationEnvironment": "applicationEnvironment",
47
+ "audienceUrl": "audienceUrl",
48
+ "authClientId": "authClientId",
49
+ "authDomain": "authDomain",
50
+ "client": {
51
+ "archiveFile": "/embeddable-sdk/packages/core-sdk",
52
+ "buildDir": "/embeddable-sdk/packages/core-sdk",
53
+ "bundleHash": undefined,
54
+ "componentDir": "/embeddable-sdk/packages/core-sdk",
55
+ "errorFallbackComponent": "/embeddable-sdk/packages/core-sdk",
56
+ "modelsSrc": "/embeddable-sdk/packages/core-sdk",
57
+ "rootDir": "/embeddable-sdk/packages/core-sdk",
58
+ "srcDir": "/embeddable-sdk/packages/core-sdk",
59
+ "stencilBuild": "/embeddable-sdk/packages/core-sdk",
60
+ "tmpDir": "/embeddable-sdk/packages/core-sdk",
61
+ },
62
+ "core": {
63
+ "configsDir": "/embeddable-sdk/packages/core-sdk",
64
+ "rootDir": "/embeddable-sdk/packages/core-sdk",
65
+ "templatesDir": "/embeddable-sdk/packages/core-sdk",
66
+ },
67
+ "outputOptions": {
68
+ "typesEntryPointFilename": "embeddable-types-entry-point.js",
69
+ },
70
+ "plugins": [],
71
+ "previewBaseUrl": "previewBaseUrl",
72
+ "pushBaseUrl": "pushBaseUrl",
73
+ "rollbarAccessToken": "rollbarAccessToken",
74
+ }
75
+ `);
76
+ });
77
+ });
package/src/dev.ts CHANGED
@@ -233,7 +233,10 @@ const sendDataModelsAndSecurityContextsChanges = async (ctx: any) => {
233
233
  const sending = ora(
234
234
  "Synchronising data models and/or security contexts...",
235
235
  ).start();
236
- const filesList = await findFiles(ctx.client.srcDir, YAML_OR_JS_FILES);
236
+ const filesList = await findFiles(
237
+ ctx.client.modelsSrc || ctx.client.srcDir,
238
+ YAML_OR_JS_FILES,
239
+ );
237
240
  await archive(ctx, filesList, false);
238
241
  await sendBuild(ctx, { workspaceId: previewWorkspace, token });
239
242
  sending.succeed(`Data models and/or security context synchronized`);
@@ -0,0 +1,115 @@
1
+ import generate from "./generate";
2
+ import * as fs from "node:fs/promises";
3
+ import * as path from "node:path";
4
+ import { checkNodeVersion } from "./utils";
5
+ import { loadConfig, createCompiler } from "@stencil/core/compiler";
6
+ import { findFiles, getContentHash } from "@embeddable.com/sdk-utils";
7
+
8
+ const config = {
9
+ client: {
10
+ rootDir: "rootDir",
11
+ srcDir: "srcDir",
12
+ buildDir: "buildDir",
13
+ tmpDir: "tmpDir",
14
+ stencilBuild: "stencilBuild",
15
+ componentDir: "componentDir",
16
+ },
17
+ core: {
18
+ rootDir: "rootDir",
19
+ templatesDir: "templatesDir",
20
+ configsDir: "configsDir",
21
+ },
22
+ "sdk-react": {
23
+ rootDir: "rootDir",
24
+ templatesDir: "templatesDir",
25
+ configsDir: "configsDir",
26
+ outputOptions: {
27
+ buildName: "buildName",
28
+ },
29
+ },
30
+ };
31
+
32
+ vi.mock("@embeddable.com/sdk-utils", () => ({
33
+ getContentHash: vi.fn(),
34
+ findFiles: vi.fn(),
35
+ }));
36
+
37
+ vi.mock("./utils", () => ({
38
+ checkNodeVersion: vi.fn(),
39
+ }));
40
+
41
+ vi.mock("./provideConfig", () => ({
42
+ provideConfig: vi.fn().mockResolvedValue(config),
43
+ }));
44
+
45
+ vi.mock("node:fs/promises", () => ({
46
+ writeFile: vi.fn(),
47
+ readdir: vi.fn(),
48
+ readFile: vi.fn(),
49
+ rename: vi.fn(),
50
+ cp: vi.fn(),
51
+ rm: vi.fn(),
52
+ }));
53
+
54
+ vi.mock("node:path", async () => {
55
+ const actual = await vi.importActual("node:path");
56
+ return {
57
+ ...actual,
58
+ resolve: vi.fn(),
59
+ join: vi.fn(),
60
+ };
61
+ });
62
+
63
+ vi.mock("@stencil/core/compiler", () => ({
64
+ createCompiler: vi.fn(),
65
+ loadConfig: vi.fn(),
66
+ }));
67
+
68
+ describe("generate", () => {
69
+ beforeEach(() => {
70
+ vi.mocked(checkNodeVersion).mockResolvedValue(true);
71
+ vi.mocked(fs.readdir).mockResolvedValue([
72
+ "embeddable-wrapper.esm.js",
73
+ "embeddable-wrapper.esm.js.map",
74
+ "styles.css",
75
+ ] as any);
76
+ vi.mocked(path.resolve).mockImplementation((...args) => args.join("/"));
77
+ vi.mocked(fs.readFile).mockResolvedValue("");
78
+ vi.mocked(loadConfig).mockResolvedValue({
79
+ config: {},
80
+ } as any);
81
+ vi.mocked(createCompiler).mockResolvedValue({
82
+ build: vi.fn(),
83
+ destroy: vi.fn(),
84
+ } as any);
85
+
86
+ vi.mocked(getContentHash).mockReturnValue("hash");
87
+ vi.mocked(findFiles).mockResolvedValue([["", ""]]);
88
+
89
+ Object.defineProperties(process, {
90
+ chdir: {
91
+ value: vi.fn(),
92
+ },
93
+ });
94
+ });
95
+
96
+ it("should generate bundle", async () => {
97
+ await generate(config, "sdk-react");
98
+
99
+ // should inject css
100
+ expect(fs.writeFile).toHaveBeenCalledWith("componentDir/style.css", "");
101
+
102
+ // should inject bundle renderer
103
+ expect(fs.writeFile).toHaveBeenCalledWith("componentDir/component.tsx", "");
104
+
105
+ expect(loadConfig).toHaveBeenCalled();
106
+
107
+ expect(createCompiler).toHaveBeenCalledWith({});
108
+
109
+ // check if the file is renamed
110
+ expect(fs.rename).toHaveBeenCalledWith(
111
+ "stencilBuild/embeddable-wrapper.esm.js",
112
+ "stencilBuild/embeddable-wrapper.esm-hash.js",
113
+ );
114
+ });
115
+ });
package/src/generate.ts CHANGED
@@ -2,13 +2,16 @@ import * as fs from "node:fs/promises";
2
2
  import * as path from "node:path";
3
3
  import { createNodeLogger, createNodeSys } from "@stencil/core/sys/node";
4
4
  import { createCompiler, loadConfig } from "@stencil/core/compiler";
5
- import { getContentHash } from "@embeddable.com/sdk-utils";
5
+ import { findFiles, getContentHash } from "@embeddable.com/sdk-utils";
6
6
 
7
7
  const sorcery = require("sorcery");
8
8
 
9
9
  const STYLE_IMPORTS_TOKEN = "{{STYLES_IMPORT}}";
10
10
  const RENDER_IMPORT_TOKEN = "{{RENDER_IMPORT}}";
11
11
 
12
+ // stencil doesn't support dynamic component tag name, so we need to replace it manually
13
+ const COMPONENT_TAG_TOKEN = "replace-this-with-component-name";
14
+
12
15
  export default async (ctx: any, pluginName: string) => {
13
16
  await injectCSS(ctx, pluginName);
14
17
 
@@ -48,17 +51,51 @@ async function injectCSS(ctx: any, pluginName: string) {
48
51
  async function injectBundleRender(ctx: any, pluginName: string) {
49
52
  const importStr = `import render from '../${ctx[pluginName].outputOptions.buildName}/${ctx[pluginName].outputOptions.fileName}';`;
50
53
 
51
- const content = await fs.readFile(
54
+ let content = await fs.readFile(
52
55
  path.resolve(ctx.core.templatesDir, "component.tsx.template"),
53
56
  "utf8",
54
57
  );
55
58
 
59
+ if (!!ctx.dev) {
60
+ content = content.replace(COMPONENT_TAG_TOKEN, "embeddable-component");
61
+ }
62
+
56
63
  await fs.writeFile(
57
64
  path.resolve(ctx.client.componentDir, "component.tsx"),
58
65
  content.replace(RENDER_IMPORT_TOKEN, importStr),
59
66
  );
60
67
  }
61
68
 
69
+ async function addComponentTagName(filePath: string, bundleHash: string) {
70
+ // find entry file with a name *.entry.js
71
+ const entryFiles = await findFiles(path.dirname(filePath), /.*\.entry\.js/);
72
+
73
+ if (!entryFiles.length) {
74
+ return;
75
+ }
76
+
77
+ const entryFileName = entryFiles[0];
78
+ const [entryFileContent, fileContent] = await Promise.all([
79
+ fs.readFile(entryFileName[1], "utf8"),
80
+ fs.readFile(filePath, "utf8"),
81
+ ]);
82
+
83
+ const newFileContent = fileContent.replace(
84
+ COMPONENT_TAG_TOKEN,
85
+ `embeddable-component-${bundleHash}`,
86
+ );
87
+
88
+ const newEntryFileContent = entryFileContent.replace(
89
+ COMPONENT_TAG_TOKEN.replaceAll("-", "_"),
90
+ `embeddable_component_${bundleHash}`,
91
+ );
92
+
93
+ await Promise.all([
94
+ fs.writeFile(filePath, newFileContent),
95
+ fs.writeFile(entryFileName[1], newEntryFileContent),
96
+ ]);
97
+ }
98
+
62
99
  async function runStencil(ctx: any) {
63
100
  const logger = ctx.dev?.logger || createNodeLogger({ process });
64
101
  const sys = ctx.dev?.sys || createNodeSys({ process });
@@ -95,12 +132,17 @@ async function runStencil(ctx: any) {
95
132
  );
96
133
 
97
134
  let fileName = "embeddable-wrapper.esm.js";
135
+
98
136
  if (!ctx.dev?.watch) {
99
137
  const entryFileContent = await fs.readFile(entryFilePath, "utf8");
100
138
 
101
139
  const fileHash = getContentHash(entryFileContent);
102
140
 
103
141
  fileName = `embeddable-wrapper.esm-${fileHash}.js`;
142
+
143
+ ctx.client.bundleHash = fileHash;
144
+
145
+ await addComponentTagName(entryFilePath, ctx.client.bundleHash);
104
146
  }
105
147
 
106
148
  await fs.rename(
package/src/rollbar.mjs CHANGED
@@ -1,10 +1,9 @@
1
- import * as path from "path";
2
- import Rollbar from 'rollbar';
1
+ import * as path from "node:path";
2
+ import Rollbar from "rollbar";
3
3
  import provideConfig from "./provideConfig";
4
- import fs from "node:fs/promises";
5
- import {CREDENTIALS_FILE} from "./credentials";
6
- import {jwtDecode} from "jwt-decode";
7
-
4
+ import * as fs from "node:fs/promises";
5
+ import { CREDENTIALS_FILE } from "./credentials";
6
+ import { jwtDecode } from "jwt-decode";
8
7
 
9
8
  const reportErrorToRollbar = async (error) => {
10
9
  const config = await provideConfig();
@@ -19,31 +18,33 @@ const reportErrorToRollbar = async (error) => {
19
18
  },
20
19
  });
21
20
 
22
- const userData = await getUserData()
21
+ const userData = await getUserData();
22
+
23
+ const sdkPackageVersion = await getSdkPackageVersionInfo(config);
23
24
 
24
25
  rollbar.configure({
25
26
  payload: {
26
- person: {
27
- id: userData.globalUserId
28
- }
29
- }
30
- })
27
+ person: {
28
+ id: userData.globalUserId,
29
+ },
30
+ },
31
+ });
31
32
 
32
- rollbar.error(error, {
33
+ return rollbar.error(error, {
33
34
  custom: {
34
- code_version: getSdkPackageVersionInfo(config)
35
+ code_version: sdkPackageVersion,
35
36
  },
36
37
  });
37
38
  };
38
39
 
39
- const getSdkPackageVersionInfo = (config) => {
40
+ const getSdkPackageVersionInfo = async (config) => {
40
41
  try {
41
42
  const packageJsonFilePath = path.resolve(
42
43
  config.client.rootDir,
43
44
  "package.json",
44
45
  );
45
46
 
46
- const packageJson = require(packageJsonFilePath);
47
+ const packageJson = await import(packageJsonFilePath);
47
48
  const devDependencies = packageJson.devDependencies;
48
49
  const dependencies = packageJson.dependencies;
49
50
 
@@ -52,15 +53,31 @@ const getSdkPackageVersionInfo = (config) => {
52
53
  };
53
54
 
54
55
  const packageVersionInfo = {
55
- core: getDependencyVersion("@embeddable.com/core", dependencies, devDependencies),
56
- sdk_core: getDependencyVersion("@embeddable.com/sdk-core", dependencies, devDependencies),
57
- react: getDependencyVersion("@embeddable.com/react", dependencies, devDependencies),
58
- sdk_react: getDependencyVersion("@embeddable.com/sdk-react", dependencies, devDependencies),
56
+ core: getDependencyVersion(
57
+ "@embeddable.com/core",
58
+ dependencies,
59
+ devDependencies,
60
+ ),
61
+ sdk_core: getDependencyVersion(
62
+ "@embeddable.com/sdk-core",
63
+ dependencies,
64
+ devDependencies,
65
+ ),
66
+ react: getDependencyVersion(
67
+ "@embeddable.com/react",
68
+ dependencies,
69
+ devDependencies,
70
+ ),
71
+ sdk_react: getDependencyVersion(
72
+ "@embeddable.com/sdk-react",
73
+ dependencies,
74
+ devDependencies,
75
+ ),
59
76
  };
60
77
 
61
78
  return JSON.stringify(packageVersionInfo);
62
79
  } catch (e) {
63
- console.warn("Could not get SDK package version info", e)
80
+ console.warn("Could not get SDK package version info", e);
64
81
  return "unknown";
65
82
  }
66
83
  };
@@ -68,8 +85,8 @@ const getSdkPackageVersionInfo = (config) => {
68
85
  export async function getUserData() {
69
86
  try {
70
87
  const token = await fs
71
- .readFile(CREDENTIALS_FILE)
72
- .then((data) => JSON.parse(data.toString()));
88
+ .readFile(CREDENTIALS_FILE)
89
+ .then((data) => JSON.parse(data.toString()));
73
90
 
74
91
  const decodedToken = jwtDecode(token.access_token);
75
92
 
@@ -0,0 +1,87 @@
1
+ // @ts-ignore
2
+ import reportErrorToRollbar from "./rollbar.mjs";
3
+ import provideConfig from "./provideConfig";
4
+ import Rollbar from "rollbar";
5
+ import * as path from "node:path";
6
+ import * as fs from "node:fs/promises";
7
+ import { jwtDecode } from "jwt-decode";
8
+ import { readFile } from "node:fs";
9
+
10
+ const config = {
11
+ applicationEnvironment: "test",
12
+ client: {
13
+ rootDir: "rootDir",
14
+ },
15
+ };
16
+
17
+ vi.mock("node:fs/promises", () => ({
18
+ writeFile: vi.fn(),
19
+ readFile: vi.fn(),
20
+ }));
21
+
22
+ vi.mock("./provideConfig", () => ({
23
+ default: vi.fn(),
24
+ }));
25
+
26
+ vi.mock("jwt-decode", () => ({
27
+ jwtDecode: vi.fn(),
28
+ }));
29
+
30
+ vi.mock("node:path", async () => {
31
+ const actual = await vi.importActual("path");
32
+ return {
33
+ ...actual,
34
+ resolve: vi.fn(),
35
+ };
36
+ });
37
+
38
+ // mock rollback constructor
39
+ vi.mock("rollbar", () => ({
40
+ default: vi.fn(),
41
+ }));
42
+
43
+ vi.mock("resolvedPath", () => ({
44
+ default: vi.fn(),
45
+ devDependencies: {
46
+ "@embeddable.com/sdk-utils": "0.1.2",
47
+ },
48
+ dependencies: {
49
+ "@embeddable.com/core": "1.0.0",
50
+ "@embeddable.com/sdk-core": "1.2.3",
51
+ },
52
+ }));
53
+
54
+ const rollbarInstanceMock = {
55
+ error: vi.fn(),
56
+ configure: vi.fn(),
57
+ };
58
+
59
+ describe("rollbar", () => {
60
+ beforeEach(() => {
61
+ vi.mocked(provideConfig).mockResolvedValue(config);
62
+ vi.mocked(Rollbar).mockReturnValue(rollbarInstanceMock as any);
63
+ vi.mocked(path.resolve).mockReturnValue("resolvedPath");
64
+
65
+ vi.mocked(fs.readFile).mockResolvedValue("{}");
66
+ vi.mocked(jwtDecode).mockReturnValue({ sub: "test", iss: "iss" });
67
+ });
68
+
69
+ it("should call Rollbar.error with the error", async () => {
70
+ const error = new Error("test error");
71
+ await reportErrorToRollbar(error);
72
+
73
+ expect(rollbarInstanceMock.configure).toHaveBeenCalledWith({
74
+ payload: {
75
+ person: {
76
+ id: "iss@test",
77
+ },
78
+ },
79
+ });
80
+
81
+ expect(rollbarInstanceMock.error).toHaveBeenCalledWith(error, {
82
+ custom: {
83
+ code_version: '{"core":"1.0.0","sdk_core":"1.2.3"}',
84
+ },
85
+ });
86
+ });
87
+ });
@@ -2,7 +2,7 @@ import { Component, Watch, Host, Prop, Event, EventEmitter, h, Listen } from '@s
2
2
  {{RENDER_IMPORT}}
3
3
 
4
4
  @Component({
5
- tag: 'embeddable-component',
5
+ tag: 'replace-this-with-component-name',
6
6
  styleUrl: './style.css',
7
7
  shadow: true,
8
8
  })