@embeddable.com/sdk-core 0.1.1 → 1.0.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.
@@ -4,49 +4,58 @@ const vite = require("vite");
4
4
 
5
5
  const { findEmbFiles } = require("./findEmbFiles");
6
6
 
7
-
8
7
  const EMB_TYPE_FILE_REGEX = /^(.*)\.type\.emb\.[jt]s$/;
8
+ const EMB_OPTIONS_FILE_REGEX = /^(.*)\.options\.emb\.[jt]s$/;
9
9
 
10
10
  async function buildTypes(ctx) {
11
- await generate(ctx);
11
+ await generate(ctx);
12
12
 
13
- await build(ctx);
13
+ await build(ctx);
14
14
 
15
- await cleanup(ctx);
15
+ await cleanup(ctx);
16
16
  }
17
17
 
18
18
  module.exports = { buildTypes };
19
19
 
20
-
21
20
  async function generate(ctx) {
22
- const typeFiles = await findEmbFiles(ctx.client.srcDir, EMB_TYPE_FILE_REGEX);
23
-
24
- const typeImports = typeFiles.map(([fileName, filePath]) =>
25
- `import './${path.relative(ctx.client.rootDir, filePath)}';`
26
- ).join('\n');
27
-
28
- await fs.writeFile(
29
- path.resolve(ctx.client.rootDir, ctx.outputOptions.typesEntryPointFilename),
30
- typeImports
31
- );
21
+ const typeFiles = await findEmbFiles(ctx.client.srcDir, EMB_TYPE_FILE_REGEX);
22
+ const optionsFiles = await findEmbFiles(
23
+ ctx.client.srcDir,
24
+ EMB_OPTIONS_FILE_REGEX,
25
+ );
26
+
27
+ const typeImports = typeFiles
28
+ .concat(optionsFiles)
29
+ .map(
30
+ ([fileName, filePath]) =>
31
+ `import './${path.relative(ctx.client.rootDir, filePath)}';`,
32
+ )
33
+ .join("\n");
34
+
35
+ await fs.writeFile(
36
+ path.resolve(ctx.client.rootDir, ctx.outputOptions.typesEntryPointFilename),
37
+ typeImports,
38
+ );
32
39
  }
33
40
 
34
41
  async function build(ctx) {
35
- process.chdir(ctx.client.rootDir);
36
-
37
- await vite.build({
38
- build: {
39
- emptyOutDir: false,
40
- lib: {
41
- entry: `./${ctx.outputOptions.typesEntryPointFilename}`,
42
- formats: ['es'],
43
- fileName: 'embeddable-types'
44
- },
45
- outDir: '.embeddable-build/'
46
- },
47
- });
42
+ process.chdir(ctx.client.rootDir);
43
+
44
+ await vite.build({
45
+ build: {
46
+ emptyOutDir: false,
47
+ lib: {
48
+ entry: `./${ctx.outputOptions.typesEntryPointFilename}`,
49
+ formats: ["es"],
50
+ fileName: "embeddable-types",
51
+ },
52
+ outDir: ".embeddable-build/",
53
+ },
54
+ });
48
55
  }
49
56
 
50
57
  async function cleanup(ctx) {
51
- await fs.rm(path.resolve(ctx.client.rootDir, 'embeddable-types-entry-point.js'));
58
+ await fs.rm(
59
+ path.resolve(ctx.client.rootDir, "embeddable-types-entry-point.js"),
60
+ );
52
61
  }
@@ -1,30 +1,27 @@
1
- const fs = require('fs/promises');
1
+ const fs = require("fs/promises");
2
2
  const path = require("path");
3
3
 
4
- async function cleanup (ctx) {
5
- await extractBuild(ctx);
4
+ async function cleanup(ctx) {
5
+ await extractBuild(ctx);
6
6
 
7
- await removeObsoleteDir(ctx.client.buildDir);
7
+ await removeObsoleteDir(ctx.client.buildDir);
8
8
 
9
- await moveBuildTOBuildDir(ctx);
9
+ await moveBuildTOBuildDir(ctx);
10
10
  }
11
11
 
12
12
  module.exports = { cleanup };
13
13
 
14
-
15
14
  async function extractBuild(ctx) {
16
- await fs.rename(
17
- path.resolve(ctx.client.buildDir, ctx.client.stencilBuild),
18
- ctx.client.tmpDir
19
- );
15
+ await fs.rename(
16
+ path.resolve(ctx.client.buildDir, ctx.client.stencilBuild),
17
+ ctx.client.tmpDir,
18
+ );
20
19
  }
21
20
 
22
-
23
21
  async function removeObsoleteDir(dir) {
24
- await fs.rm(dir, { recursive: true });
22
+ await fs.rm(dir, { recursive: true });
25
23
  }
26
24
 
27
-
28
25
  async function moveBuildTOBuildDir(ctx) {
29
- await fs.rename(ctx.client.tmpDir, ctx.client.buildDir);
26
+ await fs.rename(ctx.client.tmpDir, ctx.client.buildDir);
30
27
  }
@@ -1,22 +1,27 @@
1
- const path = require('path');
1
+ const path = require("path");
2
2
 
3
- function createContext (coreRoot, clientRoot) {
4
- return {
5
- core: {
6
- rootDir: coreRoot,
7
- templatesDir: path.resolve(coreRoot, 'templates'),
8
- configsDir: path.resolve(coreRoot, 'configs')
9
- },
10
- client: {
11
- rootDir: clientRoot,
12
- buildDir: path.resolve(clientRoot, '.embeddable-build'),
13
- srcDir: path.resolve(clientRoot, 'src'),
14
- tmpDir: path.resolve(clientRoot, '.embeddable-tmp'),
15
- componentDir: path.resolve(clientRoot, '.embeddable-build', 'component'),
16
- stencilBuild: path.resolve(clientRoot, '.embeddable-build', 'dist', 'embeddable-wrapper'),
17
- archiveFile: path.resolve(clientRoot, "embeddable-build.zip")
18
- }
19
- }
3
+ function createContext(coreRoot, clientRoot) {
4
+ return {
5
+ core: {
6
+ rootDir: coreRoot,
7
+ templatesDir: path.resolve(coreRoot, "templates"),
8
+ configsDir: path.resolve(coreRoot, "configs"),
9
+ },
10
+ client: {
11
+ rootDir: clientRoot,
12
+ buildDir: path.resolve(clientRoot, ".embeddable-build"),
13
+ srcDir: path.resolve(clientRoot, "src"),
14
+ tmpDir: path.resolve(clientRoot, ".embeddable-tmp"),
15
+ componentDir: path.resolve(clientRoot, ".embeddable-build", "component"),
16
+ stencilBuild: path.resolve(
17
+ clientRoot,
18
+ ".embeddable-build",
19
+ "dist",
20
+ "embeddable-wrapper",
21
+ ),
22
+ archiveFile: path.resolve(clientRoot, "embeddable-build.zip"),
23
+ },
24
+ };
20
25
  }
21
26
 
22
- module.exports = { createContext };
27
+ module.exports = { createContext };
@@ -1,33 +1,32 @@
1
1
  const fs = require("fs/promises");
2
2
  const path = require("path");
3
3
 
4
- async function findEmbFiles (initialSrcDir, regex) {
5
- const filesList = [];
4
+ async function findEmbFiles(initialSrcDir, regex) {
5
+ const filesList = [];
6
6
 
7
- async function findEmbFilesRec(srcDir) {
8
- const allFiles = await fs.readdir(srcDir);
7
+ async function findEmbFilesRec(srcDir) {
8
+ const allFiles = await fs.readdir(srcDir);
9
9
 
10
- for (const file of allFiles) {
11
- const filePath = path.join(srcDir, file)
10
+ for (const file of allFiles) {
11
+ const filePath = path.join(srcDir, file);
12
12
 
13
- const status = await fs.lstat(filePath);
13
+ const status = await fs.lstat(filePath);
14
14
 
15
- if (status.isDirectory()) {
16
- await findEmbFilesRec(filePath)
17
- }
15
+ if (status.isDirectory()) {
16
+ await findEmbFilesRec(filePath);
17
+ }
18
18
 
19
- const fileName = file.match(regex);
19
+ const fileName = file.match(regex);
20
20
 
21
- if (fileName) {
22
- filesList.push([fileName[1], filePath]);
23
- }
24
- }
21
+ if (fileName) {
22
+ filesList.push([fileName[1], filePath]);
23
+ }
25
24
  }
25
+ }
26
26
 
27
- await findEmbFilesRec(initialSrcDir);
27
+ await findEmbFilesRec(initialSrcDir);
28
28
 
29
-
30
- return filesList;
29
+ return filesList;
31
30
  }
32
31
 
33
32
  module.exports = { findEmbFiles };
@@ -4,64 +4,69 @@ const path = require("path");
4
4
  const stencilNodeApi = require("@stencil/core/sys/node");
5
5
  const stencil = require("@stencil/core/cli");
6
6
 
7
- const STYLE_IMPORTS_TOKEN = '{{STYLES_IMPORT}}';
8
- const RENDER_IMPORT_TOKEN = '{{RENDER_IMPORT}}';
7
+ const STYLE_IMPORTS_TOKEN = "{{STYLES_IMPORT}}";
8
+ const RENDER_IMPORT_TOKEN = "{{RENDER_IMPORT}}";
9
9
 
10
10
  const NODE_LOGGER = stencilNodeApi.createNodeLogger({ process: process });
11
- const NODE_SYS = stencilNodeApi.createNodeSys({ process: process, logger: NODE_LOGGER });
11
+ const NODE_SYS = stencilNodeApi.createNodeSys({
12
+ process: process,
13
+ logger: NODE_LOGGER,
14
+ });
12
15
 
13
16
  async function generate(ctx) {
14
- await injectCSS(ctx);
17
+ await injectCSS(ctx);
15
18
 
16
- await injectBundleRender(ctx);
19
+ await injectBundleRender(ctx);
17
20
 
18
- await runStencil(ctx);
21
+ await runStencil(ctx);
19
22
  }
20
23
 
21
24
  module.exports = { generate };
22
25
 
23
- async function injectCSS (ctx) {
24
- const CUSTOMER_BUILD = path.resolve(ctx.client.buildDir, ctx.pluginOptions.outDir);
25
- const allFiles = await fs.readdir(CUSTOMER_BUILD);
26
-
27
- const cssFilesImportsStr = allFiles
28
- .filter(fileName => fileName.endsWith('.css'))
29
- .map(fileName => `@import '../${ctx.pluginOptions.outDir}/${fileName}';`).join('\n');
30
-
31
- const content = await fs.readFile(
32
- path.resolve(ctx.core.templatesDir, 'style.css.template'),
33
- 'utf8'
34
- );
35
-
36
- await fs.writeFile(
37
- path.resolve(ctx.client.componentDir, 'style.css'),
38
- content.replace(STYLE_IMPORTS_TOKEN, cssFilesImportsStr)
39
- );
26
+ async function injectCSS(ctx) {
27
+ const CUSTOMER_BUILD = path.resolve(
28
+ ctx.client.buildDir,
29
+ ctx.pluginOptions.outDir,
30
+ );
31
+ const allFiles = await fs.readdir(CUSTOMER_BUILD);
32
+
33
+ const cssFilesImportsStr = allFiles
34
+ .filter((fileName) => fileName.endsWith(".css"))
35
+ .map((fileName) => `@import '../${ctx.pluginOptions.outDir}/${fileName}';`)
36
+ .join("\n");
37
+
38
+ const content = await fs.readFile(
39
+ path.resolve(ctx.core.templatesDir, "style.css.template"),
40
+ "utf8",
41
+ );
42
+
43
+ await fs.writeFile(
44
+ path.resolve(ctx.client.componentDir, "style.css"),
45
+ content.replace(STYLE_IMPORTS_TOKEN, cssFilesImportsStr),
46
+ );
40
47
  }
41
48
 
42
-
43
49
  async function injectBundleRender(ctx) {
44
- const importStr = `import render from '../${ctx.pluginOptions.outDir}/${ctx.pluginOptions.renderFunctionFileName}';`;
50
+ const importStr = `import render from '../${ctx.pluginOptions.outDir}/${ctx.pluginOptions.renderFunctionFileName}';`;
45
51
 
46
- const content = await fs.readFile(
47
- path.resolve(ctx.core.templatesDir, 'component.tsx.template'),
48
- 'utf8'
49
- );
52
+ const content = await fs.readFile(
53
+ path.resolve(ctx.core.templatesDir, "component.tsx.template"),
54
+ "utf8",
55
+ );
50
56
 
51
- await fs.writeFile(
52
- path.resolve(ctx.client.componentDir, 'component.tsx'),
53
- content.replace(RENDER_IMPORT_TOKEN, importStr)
54
- );
57
+ await fs.writeFile(
58
+ path.resolve(ctx.client.componentDir, "component.tsx"),
59
+ content.replace(RENDER_IMPORT_TOKEN, importStr),
60
+ );
55
61
  }
56
62
 
57
-
58
63
  async function runStencil(ctx) {
59
- process.chdir(ctx.client.buildDir);
60
-
61
- await stencil.run({
62
- args: ['build'],
63
- logger: NODE_LOGGER,
64
- sys: NODE_SYS,
65
- checkVersion: stencilNodeApi.checkVersion,
66
- });
67
- }
64
+ process.chdir(ctx.client.buildDir);
65
+
66
+ await stencil.run({
67
+ args: ["build"],
68
+ logger: NODE_LOGGER,
69
+ sys: NODE_SYS,
70
+ checkVersion: stencilNodeApi.checkVersion,
71
+ });
72
+ }
@@ -0,0 +1,13 @@
1
+ const fsP = require("node:fs/promises");
2
+ const fs = require("node:fs")
3
+ const path = require("node:path");
4
+ async function globalCleanup(ctx) {
5
+ const componentsEntryPath = path.resolve(ctx.client.rootDir, ctx.outputOptions.componentsEntryPointFilename);
6
+ const typesEntryPath = path.resolve(ctx.client.rootDir, ctx.outputOptions.typesEntryPointFilename);
7
+
8
+ if (fs.existsSync(ctx.client.buildDir)) await fsP.rm(ctx.client.buildDir, { recursive: true });
9
+ if (fs.existsSync(componentsEntryPath)) await fsP.rm(componentsEntryPath);
10
+ if (fs.existsSync(typesEntryPath)) await fsP.rm(typesEntryPath);
11
+ }
12
+
13
+ module.exports = { globalCleanup };
package/scripts/index.js CHANGED
@@ -3,11 +3,15 @@ const { buildTypes } = require("./buildTypes");
3
3
  const { findEmbFiles } = require("./findEmbFiles");
4
4
  const { login } = require("./login");
5
5
  const { push } = require("./push");
6
+ const { validate } = require("./validate");
7
+ const { globalCleanup } = require("./globalCleanup");
6
8
 
7
9
  module.exports = {
8
- build,
9
- buildTypes,
10
- findEmbFiles,
11
- login,
12
- push
13
- }
10
+ build,
11
+ buildTypes,
12
+ findEmbFiles,
13
+ login,
14
+ push,
15
+ validate,
16
+ globalCleanup,
17
+ };
package/scripts/login.js CHANGED
@@ -1,76 +1,93 @@
1
1
  const path = require("path");
2
2
  const os = require("os");
3
3
  const fs = require("fs/promises");
4
- const prompt = require('prompt');
5
- const axios = require('axios');
6
-
7
- const CREDENTIALS_DIR = path.resolve(os.homedir(), '.embeddable');
8
- const CREDENTIALS_FILE = path.resolve(CREDENTIALS_DIR, 'credentials');
9
-
10
- const PROMPT_SCHEMA = {
11
- properties: {
12
- username: {
13
- description: 'embeddable user name',
14
- type: 'string',
15
- required: true
16
- },
17
- password: {
18
- description: 'embeddable user password',
19
- type: 'string',
20
- hidden: true,
21
- replace: '*',
22
- required: true
23
- }
24
- }
25
- };
4
+ const axios = require("axios");
5
+ const oraP = import("ora");
6
+ const openP = import("open");
26
7
 
27
- async function login () {
28
- await resolveFiles();
8
+ const CREDENTIALS_DIR = path.resolve(os.homedir(), ".embeddable");
9
+ const CREDENTIALS_FILE = path.resolve(CREDENTIALS_DIR, "credentials");
29
10
 
30
- prompt.start();
11
+ const AUTH0_DOMAIN = "embeddable-dev.eu.auth0.com";
12
+ const AUTH0_CLIENT_ID = "xOKco5ztFCpWn54bJbFkAcT8mV4LLcpG";
31
13
 
32
- const { username, password } = await prompt.get(PROMPT_SCHEMA);
14
+ async function login() {
15
+ const ora = (await oraP).default;
16
+ const open = (await openP).default
33
17
 
34
- const authResponse = await axios.post(
35
- 'https://metadata.embeddable.com/auth/token', // TODO: hardcoded for now.
36
- { username, password }
37
- );
18
+ await resolveFiles();
38
19
 
39
- const token = authResponse.data;
20
+ const deviceCodePayload = {
21
+ client_id: AUTH0_CLIENT_ID,
22
+ audience: "https://api.embeddable.com/",
23
+ };
40
24
 
41
- if (!token) {
42
- prompt.stop();
43
- console.log('Invalid credentials');
44
- process.exit();
45
- }
25
+ const deviceCodeResponse = await axios.post(
26
+ `https://${AUTH0_DOMAIN}/oauth/device/code`,
27
+ deviceCodePayload,
28
+ );
46
29
 
47
- await fs.writeFile(CREDENTIALS_FILE, JSON.stringify({ token }));
48
- }
30
+ const tokenPayload = {
31
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
32
+ device_code: deviceCodeResponse.data["device_code"],
33
+ client_id: AUTH0_CLIENT_ID,
34
+ };
49
35
 
50
- async function getToken() {
36
+ const authenticationSpinner = ora("waiting for code verification...").start();
37
+
38
+ await open(deviceCodeResponse.data["verification_uri_complete"]);
39
+
40
+ /**
41
+ * This is a recommended way to poll, since it take some time for a user to enter a `user_code` in a browser.
42
+ * deviceCodeResponse.data['interval'] is a recommended/calculated polling interval specified in seconds.
43
+ */
44
+ while (true) {
51
45
  try {
52
- const rawCredentials = await fs.readFile(CREDENTIALS_FILE, 'utf-8');
53
- const credentials = JSON.parse(rawCredentials.toString());
46
+ const tokenResponse = await axios.post(
47
+ `https://${AUTH0_DOMAIN}/oauth/token`,
48
+ tokenPayload,
49
+ );
50
+ await fs.writeFile(CREDENTIALS_FILE, JSON.stringify(tokenResponse.data));
51
+ authenticationSpinner.succeed("you are successfully authenticated now!");
52
+ break;
53
+ } catch (e) {
54
+ if (e.response.data?.error !== "authorization_pending") {
55
+ authenticationSpinner.fail("authentication failed. please try again.");
56
+ process.exit(1);
57
+ }
54
58
 
55
- return credentials?.token ?? '';
56
- } catch (_e) {
57
- return '';
59
+ await sleep(deviceCodeResponse.data["interval"] * 1000);
58
60
  }
61
+ }
62
+ }
63
+
64
+ async function getToken() {
65
+ try {
66
+ const rawCredentials = await fs.readFile(CREDENTIALS_FILE, "utf-8");
67
+ const credentials = JSON.parse(rawCredentials.toString());
68
+
69
+ return credentials?.access_token ?? "";
70
+ } catch (_e) {
71
+ return "";
72
+ }
59
73
  }
60
74
 
61
75
  module.exports = { login, getToken };
62
76
 
77
+ function sleep(ms) {
78
+ return new Promise((res) => setTimeout(res, ms));
79
+ }
63
80
 
64
- async function resolveFiles () {
65
- try {
66
- await fs.access(CREDENTIALS_DIR);
67
- } catch (_e) {
68
- await fs.mkdir(CREDENTIALS_DIR);
69
- }
81
+ async function resolveFiles() {
82
+ try {
83
+ await fs.access(CREDENTIALS_DIR);
84
+ } catch (_e) {
85
+ await fs.mkdir(CREDENTIALS_DIR);
86
+ }
70
87
 
71
- try {
72
- await fs.access(CREDENTIALS_FILE);
73
- } catch (e) {
74
- await fs.writeFile(CREDENTIALS_FILE, '');
75
- }
88
+ try {
89
+ await fs.access(CREDENTIALS_FILE);
90
+ } catch (e) {
91
+ await fs.writeFile(CREDENTIALS_FILE, "");
92
+ }
76
93
  }
@@ -1,26 +1,27 @@
1
- const fsSync = require('fs');
2
- const fs = require('fs/promises');
1
+ const fsSync = require("fs");
2
+ const fs = require("fs/promises");
3
3
 
4
- async function prepare (ctx) {
5
- await removeIfExists(ctx);
4
+ async function prepare(ctx) {
5
+ await removeIfExists(ctx);
6
6
 
7
- await copyStencilConfigsToClient(ctx);
7
+ await copyStencilConfigsToClient(ctx);
8
8
 
9
- await createComponentDir(ctx.client.componentDir);
9
+ await createComponentDir(ctx.client.componentDir);
10
10
  }
11
11
 
12
- module.exports = { prepare }
12
+ module.exports = { prepare };
13
13
 
14
14
  async function removeIfExists(ctx) {
15
- if (ctx.pluginOptions) return;
15
+ if (ctx.pluginOptions) return;
16
16
 
17
- if (fsSync.existsSync(ctx.client.buildDir)) await fs.rm(ctx.client.buildDir, { recursive: true });
17
+ if (fsSync.existsSync(ctx.client.buildDir))
18
+ await fs.rm(ctx.client.buildDir, { recursive: true });
18
19
  }
19
20
 
20
21
  async function copyStencilConfigsToClient(ctx) {
21
- await fs.cp(ctx.core.configsDir, ctx.client.buildDir, { recursive: true });
22
+ await fs.cp(ctx.core.configsDir, ctx.client.buildDir, { recursive: true });
22
23
  }
23
24
 
24
25
  async function createComponentDir(dir) {
25
- await fs.mkdir(dir);
26
- }
26
+ await fs.mkdir(dir);
27
+ }