@embeddable.com/sdk-react 3.10.13 → 3.11.0-next.1

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/lib/index.esm.js CHANGED
@@ -6,7 +6,7 @@ import * as vite from 'vite';
6
6
  import ora from 'ora';
7
7
  import viteReactPlugin from '@vitejs/plugin-react';
8
8
  import * as fs from 'node:fs/promises';
9
- import { readdir, lstat, rm } from 'node:fs/promises';
9
+ import { readdir, lstat, readFile, rm } from 'node:fs/promises';
10
10
  import * as url from 'node:url';
11
11
  import { GlobalRegistrator } from '@happy-dom/global-registrator';
12
12
  import 'node:child_process';
@@ -15,6 +15,8 @@ import { z } from 'zod';
15
15
  import { parse } from '@babel/parser';
16
16
  import traverse from '@babel/traverse';
17
17
  import * as fs$1 from 'fs';
18
+ import { existsSync } from 'node:fs';
19
+ import dts from 'vite-plugin-dts';
18
20
 
19
21
  var createContext = (pluginRoot, coreCtx) => {
20
22
  coreCtx["sdk-react"] = {
@@ -38,6 +40,72 @@ const loadComponentMeta = async (moduleId) => {
38
40
  return module.meta;
39
41
  };
40
42
 
43
+ /**
44
+ * TODO: for some reason code from @embeddable.com/extract-components-config
45
+ * is being cached. Thus we use this code duplication in place. Please investigate and fix.
46
+ */
47
+ var extractComponentsConfigPlugin = ({ globalKey, outputDir, fileName, componentFileRegex, isDev = false, searchEntry = "", useBundleHash = true, ctx, externalComponents = [], }) => {
48
+ let configs = [];
49
+ return {
50
+ name: "extract-components-config",
51
+ moduleParsed: async (moduleInfo) => {
52
+ var _a;
53
+ if (componentFileRegex.test(moduleInfo.id) &&
54
+ ((_a = moduleInfo.code) === null || _a === void 0 ? void 0 : _a.includes(searchEntry))) {
55
+ try {
56
+ const meta = await loadComponentMeta(moduleInfo.id);
57
+ const configJSON = buildConfigJson(meta);
58
+ configs.push(configJSON);
59
+ }
60
+ catch (error) {
61
+ console.log("Error parsing component meta: ", moduleInfo.id);
62
+ console.error(error);
63
+ }
64
+ }
65
+ },
66
+ buildEnd: async () => {
67
+ for (const [_, externalComponent] of externalComponents) {
68
+ const meta = await loadComponentMeta(externalComponent);
69
+ configs.push(buildConfigJson(meta));
70
+ }
71
+ configs.sort((a, b) => a.localeCompare(b));
72
+ const contentString = configs.filter(Boolean).join(",\n");
73
+ let newFileName = fileName;
74
+ const bundleHash = ctx.client.bundleHash;
75
+ if (!isDev && bundleHash) {
76
+ const fileHashExtension = `-${bundleHash}.js`;
77
+ newFileName = `${fileName.replace(".js", fileHashExtension)}`;
78
+ }
79
+ let template;
80
+ if (useBundleHash && bundleHash) {
81
+ template = `
82
+ globalThis.__EMBEDDABLE__ = globalThis.__EMBEDDABLE__ || {};
83
+ globalThis.__EMBEDDABLE__["${bundleHash}"] = globalThis.__EMBEDDABLE__["${bundleHash}"] || {};
84
+ globalThis.__EMBEDDABLE__["${bundleHash}"].${globalKey} = globalThis.__EMBEDDABLE__["${bundleHash}"].${globalKey} || [
85
+ __PLACEHOLDER__
86
+ ];
87
+ globalThis.__EMBEDDABLE_BUNDLE_HASH__ = "${bundleHash}";
88
+ `;
89
+ }
90
+ else {
91
+ template = `
92
+ globalThis.__EMBEDDABLE__ = globalThis.__EMBEDDABLE__ || {};
93
+ globalThis.__EMBEDDABLE__.${globalKey} = globalThis.__EMBEDDABLE__.${globalKey} || [
94
+ __PLACEHOLDER__
95
+ ];
96
+ `;
97
+ }
98
+ await fs.writeFile(`${outputDir}/${newFileName}`, template.replace("__PLACEHOLDER__", contentString));
99
+ configs = [];
100
+ },
101
+ };
102
+ };
103
+ const buildConfigJson = (meta) => {
104
+ return JSON.stringify(meta, (_key, value) => typeof value === "object" && value !== null && "__embeddableType" in value
105
+ ? value.toString()
106
+ : value);
107
+ };
108
+
41
109
  var findFiles = async (initialSrcDir, regex) => {
42
110
  const filesList = [];
43
111
  async function findFilesRec(srcDir) {
@@ -289,7 +357,7 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
289
357
  var errorUtil;
290
358
  (function (errorUtil) {
291
359
  errorUtil.errToObj = (message) => typeof message === "string" ? { message } : message || {};
292
- errorUtil.toString = (message) => typeof message === "string" ? message : message === null || message === undefined ? undefined : message.message;
360
+ errorUtil.toString = (message) => typeof message === "string" ? message : message === null || message === void 0 ? void 0 : message.message;
293
361
  })(errorUtil || (errorUtil = {}));
294
362
  var ZodFirstPartyTypeKind;
295
363
  (function (ZodFirstPartyTypeKind) {
@@ -374,54 +442,44 @@ const getContentHash = (contentString) => {
374
442
  .substring(0, 5);
375
443
  };
376
444
 
377
- /**
378
- * TODO: for some reason code from @embeddable.com/extract-components-config
379
- * is being cached. Thus we use this code duplication in place. Please investigate and fix.
380
- */
381
- var extractComponentsConfigPlugin = ({ globalKey, outputDir, fileName, componentFileRegex, isDev = false, searchEntry = "", }) => {
382
- let configs = [];
445
+ const loadJson = async (filePath) => {
446
+ const data = await readFile(filePath, "utf-8");
447
+ return JSON.parse(data);
448
+ };
449
+
450
+ const getComponentLibraryConfig = (componentLibrary) => {
451
+ let libraryName = componentLibrary;
452
+ const include = [];
453
+ const exclude = [];
454
+ if (typeof componentLibrary === "object" && componentLibrary !== null) {
455
+ libraryName = componentLibrary.name;
456
+ if (componentLibrary.include) {
457
+ include.push(...componentLibrary.include);
458
+ }
459
+ if (componentLibrary.exclude) {
460
+ exclude.push(...componentLibrary.exclude);
461
+ }
462
+ }
463
+ return { libraryName, include, exclude };
464
+ };
465
+ const EXTERNAL_LIBRARY_META_FILE_NAME = "embeddable-components.json";
466
+ const getComponentLibraryMeta = async (ctx, componentLibrary) => {
467
+ const { libraryName, include, exclude } = getComponentLibraryConfig(componentLibrary);
468
+ const libraryMeta = (await loadJson(getLibraryPath(ctx, libraryName, EXTERNAL_LIBRARY_META_FILE_NAME)));
469
+ const filterItems = (items) => {
470
+ let result = items;
471
+ if (include.length > 0) {
472
+ result = result.filter((item) => include.includes(item));
473
+ }
474
+ return result.filter((item) => !exclude.includes(item));
475
+ };
383
476
  return {
384
- name: "extract-components-config",
385
- moduleParsed: async (moduleInfo) => {
386
- var _a;
387
- if (componentFileRegex.test(moduleInfo.id) &&
388
- ((_a = moduleInfo.code) === null || _a === undefined ? undefined : _a.includes(searchEntry))) {
389
- try {
390
- const meta = await loadComponentMeta(moduleInfo.id);
391
- const configJSON = JSON.stringify(meta, (_key, value) => typeof value === "object" &&
392
- value !== null &&
393
- "__embeddableType" in value
394
- ? value.toString()
395
- : value);
396
- configs.push(configJSON);
397
- }
398
- catch (error) {
399
- console.log("Error parsing component meta: ", moduleInfo.id);
400
- console.error(error);
401
- }
402
- }
403
- },
404
- buildEnd: async () => {
405
- const template = `
406
- globalThis.__EMBEDDABLE__ = globalThis.__EMBEDDABLE__ || {};
407
- globalThis.__EMBEDDABLE__.${globalKey} = globalThis.__EMBEDDABLE__.${globalKey} || [
408
- __PLACEHOLDER__
409
- ];
410
- `;
411
- // sort to make sure the hash is consistent
412
- configs.sort((a, b) => a.localeCompare(b));
413
- const contentString = configs.filter(Boolean).join(",\n");
414
- let newFileName = fileName;
415
- if (!isDev) {
416
- const fileHash = getContentHash(contentString);
417
- const fileHashExtention = `-${fileHash}.js`;
418
- newFileName = `${fileName.replace(".js", fileHashExtention)}`;
419
- }
420
- await fs.writeFile(`${outputDir}/${newFileName}`, template.replace("__PLACEHOLDER__", contentString));
421
- configs = [];
422
- },
477
+ ...libraryMeta,
478
+ components: filterItems(libraryMeta.components),
479
+ editors: filterItems(libraryMeta.editors),
423
480
  };
424
481
  };
482
+ const getLibraryPath = (ctx, libraryName, fileName) => path.resolve(ctx.client.rootDir, "node_modules", libraryName, "dist", fileName);
425
483
 
426
484
  const DEFAULT_LOCALE = "en-US";
427
485
  const createBuiltInType = (name, typeConfig = {}) => ({
@@ -660,7 +718,7 @@ const validateComponentProps = (metaInfo) => {
660
718
  var _a;
661
719
  const componentConfig = path.node.declaration
662
720
  .arguments[2];
663
- const propsNode = (_a = componentConfig.properties) === null || _a === undefined ? undefined : _a.find((x) => { var _a; return ((_a = x.key) === null || _a === undefined ? undefined : _a.name) === "props"; });
721
+ const propsNode = (_a = componentConfig.properties) === null || _a === void 0 ? void 0 : _a.find((x) => { var _a; return ((_a = x.key) === null || _a === void 0 ? void 0 : _a.name) === "props"; });
664
722
  // There is no props defined
665
723
  if (!propsNode)
666
724
  return;
@@ -689,7 +747,7 @@ const validateComponentProps = (metaInfo) => {
689
747
  };
690
748
  const validateComponentEvents = (metaInfo) => {
691
749
  var _a, _b;
692
- const definedEvents = (_b = (_a = metaInfo.meta.events) === null || _a === undefined ? undefined : _a.map((e) => e.name)) !== null && _b !== undefined ? _b : [];
750
+ const definedEvents = (_b = (_a = metaInfo.meta.events) === null || _a === void 0 ? void 0 : _a.map((e) => e.name)) !== null && _b !== void 0 ? _b : [];
693
751
  let implementedEvents = [];
694
752
  const errors = [];
695
753
  parseAndTraverse(metaInfo.moduleInfo.code, {
@@ -697,9 +755,9 @@ const validateComponentEvents = (metaInfo) => {
697
755
  var _a, _b, _c, _d;
698
756
  const componentConfig = path.node.declaration
699
757
  .arguments[2];
700
- const eventsNode = (_a = componentConfig.properties) === null || _a === undefined ? undefined : _a.find((p) => { var _a; return ((_a = p.key) === null || _a === undefined ? undefined : _a.name) === "events"; });
758
+ const eventsNode = (_a = componentConfig.properties) === null || _a === void 0 ? void 0 : _a.find((p) => { var _a; return ((_a = p.key) === null || _a === void 0 ? void 0 : _a.name) === "events"; });
701
759
  implementedEvents =
702
- (_d = (_c = (_b = eventsNode === null || eventsNode === undefined ? undefined : eventsNode.value) === null || _b === undefined ? undefined : _b.properties) === null || _c === undefined ? undefined : _c.map((p) => p.key.name)) !== null && _d !== undefined ? _d : [];
760
+ (_d = (_c = (_b = eventsNode === null || eventsNode === void 0 ? void 0 : eventsNode.value) === null || _b === void 0 ? void 0 : _b.properties) === null || _c === void 0 ? void 0 : _c.map((p) => p.key.name)) !== null && _d !== void 0 ? _d : [];
703
761
  },
704
762
  });
705
763
  const definedEventsSet = new Set(definedEvents);
@@ -746,7 +804,7 @@ const validateVariableInputs = (meta) => {
746
804
  const inputs = variableConfig.inputs;
747
805
  if (inputs) {
748
806
  inputs.forEach((input, inputIdx) => {
749
- const definedInput = definedInputs === null || definedInputs === undefined ? undefined : definedInputs.find((d) => d.name === input);
807
+ const definedInput = definedInputs === null || definedInputs === void 0 ? void 0 : definedInputs.find((d) => d.name === input);
750
808
  if (!definedInput) {
751
809
  const path = formatErrorPath(["variables", idx, "inputs", inputIdx]);
752
810
  errors.push(`${path}: input "${input}" is not defined`);
@@ -766,7 +824,7 @@ const validateVariableEvents = (meta) => {
766
824
  const events = variableConfig.events;
767
825
  if (events) {
768
826
  events.forEach((event, eventIdx) => {
769
- const definedEvent = definedEvents === null || definedEvents === undefined ? undefined : definedEvents.find((d) => d.name === event.name);
827
+ const definedEvent = definedEvents === null || definedEvents === void 0 ? void 0 : definedEvents.find((d) => d.name === event.name);
770
828
  if (!definedEvent) {
771
829
  const path = formatErrorPath([
772
830
  "variables",
@@ -779,7 +837,7 @@ const validateVariableEvents = (meta) => {
779
837
  return;
780
838
  }
781
839
  const definedProperties = definedEvent.properties;
782
- const definedProperty = definedProperties === null || definedProperties === undefined ? undefined : definedProperties.find((p) => p.name === event.property);
840
+ const definedProperty = definedProperties === null || definedProperties === void 0 ? void 0 : definedProperties.find((p) => p.name === event.property);
783
841
  if (!definedProperty) {
784
842
  const path = formatErrorPath([
785
843
  "variables",
@@ -812,10 +870,10 @@ const validators = {
812
870
  };
813
871
  const getModuleType = (moduleInfo) => {
814
872
  var _a, _b;
815
- if ((_a = moduleInfo.code) === null || _a === undefined ? undefined : _a.includes("defineComponent")) {
873
+ if ((_a = moduleInfo.code) === null || _a === void 0 ? void 0 : _a.includes("defineComponent")) {
816
874
  return COMPONENT;
817
875
  }
818
- else if ((_b = moduleInfo.code) === null || _b === undefined ? undefined : _b.includes("defineEditor")) {
876
+ else if ((_b = moduleInfo.code) === null || _b === void 0 ? void 0 : _b.includes("defineEditor")) {
819
877
  return EDITOR;
820
878
  }
821
879
  else {
@@ -879,7 +937,8 @@ const styledComponentsEntrypointModifier = {
879
937
  const packageJsonFilePath = path.resolve(ctx.client.rootDir, "package.json");
880
938
  try {
881
939
  const packageJson = JSON.parse(await fs.readFile(packageJsonFilePath, "utf-8"));
882
- return !!(((_a = packageJson.dependencies) === null || _a === void 0 ? void 0 : _a["styled-components"]) || ((_b = packageJson.devDependencies) === null || _b === void 0 ? void 0 : _b["styled-components"]));
940
+ return !!(((_a = packageJson.dependencies) === null || _a === void 0 ? void 0 : _a["styled-components"]) ||
941
+ ((_b = packageJson.devDependencies) === null || _b === void 0 ? void 0 : _b["styled-components"]));
883
942
  }
884
943
  catch (error) {
885
944
  console.error("styledComponentsEntrypointModifier: Error reading package.json", error);
@@ -936,7 +995,7 @@ const regexDefineTypeFunction = /defineType\(/;
936
995
  const regexDefineOptionFunction = /defineOption\(/;
937
996
  const regexCubeFunction = /cube\(/;
938
997
  const regexCubes = /cubes:/;
939
- const usageValidator = async (directory) => {
998
+ const usageValidator = async (directory, validateCube = true) => {
940
999
  let isValid = true;
941
1000
  const progress = ora("React: function usage validating...").start();
942
1001
  // defineComponent function
@@ -960,19 +1019,21 @@ const usageValidator = async (directory) => {
960
1019
  progress.fail("React: defineOption() usage is only allowed inside files with the extension .type.emb.(js|ts) files.\nFix the following files:\n" +
961
1020
  filesWithWrongDefineOptionFunctionUsage.join("\n"));
962
1021
  }
963
- // cube function
964
- const filesWithWrongCubeFunctionUsage = findFilesWithWrongUsage(directory, regexCubeFunction, [".cube.js", ".cube.ts"]);
965
- if (filesWithWrongCubeFunctionUsage.length) {
966
- isValid = false;
967
- progress.fail("React: cube() usage is only allowed inside files with the extension .cube.(ts|js) files.\nFix the following files:\n" +
968
- filesWithWrongCubeFunctionUsage.join("\n"));
969
- }
970
- // cube in yml or yaml files
971
- const filesWithWrongCubeUsage = findFilesWithWrongUsage(directory, regexCubes, [".cube.yml", ".cube.yaml"]);
972
- if (filesWithWrongCubeUsage.length) {
973
- isValid = false;
974
- progress.fail("React: cubes: usage is only allowed inside files with the extension .cube.(yml|yaml) files.\nFix the following files:\n" +
975
- filesWithWrongCubeUsage.join("\n"));
1022
+ if (validateCube) {
1023
+ // cube function
1024
+ const filesWithWrongCubeFunctionUsage = findFilesWithWrongUsage(directory, regexCubeFunction, [".cube.js", ".cube.ts"]);
1025
+ if (filesWithWrongCubeFunctionUsage.length) {
1026
+ isValid = false;
1027
+ progress.fail("React: cube() usage is only allowed inside files with the extension .cube.(ts|js) files.\nFix the following files:\n" +
1028
+ filesWithWrongCubeFunctionUsage.join("\n"));
1029
+ }
1030
+ // cube in yml or yaml files
1031
+ const filesWithWrongCubeUsage = findFilesWithWrongUsage(directory, regexCubes, [".cube.yml", ".cube.yaml"]);
1032
+ if (filesWithWrongCubeUsage.length) {
1033
+ isValid = false;
1034
+ progress.fail("React: cubes: usage is only allowed inside files with the extension .cube.(yml|yaml) files.\nFix the following files:\n" +
1035
+ filesWithWrongCubeUsage.join("\n"));
1036
+ }
976
1037
  }
977
1038
  const typeNames = findTypeNames(directory);
978
1039
  // check for definedTypes using a native typeNames
@@ -1005,14 +1066,65 @@ const usageValidator = async (directory) => {
1005
1066
  : process.exit(1);
1006
1067
  };
1007
1068
 
1069
+ const validateComponentDuplicates = (filesList, additionalComponents, ora) => {
1070
+ const progress = ora("React: validating component names...").start();
1071
+ const errors = [];
1072
+ // Ensure filesList components are unique
1073
+ const filesSet = new Set();
1074
+ for (const [componentName] of filesList) {
1075
+ if (filesSet.has(componentName)) {
1076
+ errors.push(`Error: Component '${componentName}' must be unique.`);
1077
+ }
1078
+ else {
1079
+ filesSet.add(componentName);
1080
+ }
1081
+ }
1082
+ // Ensure no filesList component exists in additionalComponents values
1083
+ for (const [componentName] of filesList) {
1084
+ for (const [library, components] of Object.entries(additionalComponents)) {
1085
+ if (components.includes(componentName)) {
1086
+ errors.push(`Error: Component '${componentName}' must be unique but is already present in library '${library}'.`);
1087
+ }
1088
+ }
1089
+ }
1090
+ // Ensure additionalComponents values are unique across different keys
1091
+ const componentToLibraries = {};
1092
+ for (const [library, components] of Object.entries(additionalComponents)) {
1093
+ for (const component of components) {
1094
+ if (!componentToLibraries[component]) {
1095
+ componentToLibraries[component] = [];
1096
+ }
1097
+ componentToLibraries[component].push(library);
1098
+ }
1099
+ }
1100
+ for (const [component, libraries] of Object.entries(componentToLibraries)) {
1101
+ if (libraries.length > 1) {
1102
+ errors.push(`Error: Component '${component}' is declared in multiple libraries: ${libraries.join(", ")}.`);
1103
+ }
1104
+ }
1105
+ if (errors.length > 0) {
1106
+ progress.fail("Validation errors found:\n");
1107
+ console.error(errors.join("\n"));
1108
+ }
1109
+ else {
1110
+ progress.succeed("Validation completed successfully. No issues found.");
1111
+ }
1112
+ return errors;
1113
+ };
1114
+
1008
1115
  const EMB_FILE_REGEX = /^(.*)(?<!\.type|\.options)\.emb\.[jt]s$/;
1009
1116
  var generate = async (ctx) => {
1010
1117
  var _a;
1011
1118
  await usageValidator(ctx.client.srcDir);
1012
1119
  const filesList = await findFiles(ctx.client.srcDir, EMB_FILE_REGEX);
1013
- await prepareEntrypoint(ctx, filesList);
1120
+ const additionalComponents = await getAdditionalComponents$1(ctx);
1121
+ const errors = validateComponentDuplicates(filesList, additionalComponents, ora);
1122
+ if (errors.length) {
1123
+ process.exit(1);
1124
+ }
1125
+ await prepareEntrypoint(ctx, filesList, additionalComponents);
1014
1126
  let result;
1015
- if ((_a = ctx.dev) === null || _a === undefined ? undefined : _a.watch) {
1127
+ if ((_a = ctx.dev) === null || _a === void 0 ? void 0 : _a.watch) {
1016
1128
  result = await runViteWatch(ctx);
1017
1129
  }
1018
1130
  else {
@@ -1022,34 +1134,15 @@ var generate = async (ctx) => {
1022
1134
  }
1023
1135
  return result;
1024
1136
  };
1025
- async function runViteBuild(ctx, watch = null) {
1137
+ function getViteConfig(ctx, watch, plugins) {
1026
1138
  var _a;
1027
- return await vite.build({
1028
- logLevel: !!watch ? "info" : "error",
1139
+ return {
1140
+ logLevel: (!!watch ? "info" : "error"),
1029
1141
  resolve: {
1030
1142
  extensions: [".ts", ".tsx", ".js", ".jsx", ".json"],
1031
- ...(_a = ctx.client.viteConfig) === null || _a === undefined ? undefined : _a.resolve,
1143
+ ...(_a = ctx.client.viteConfig) === null || _a === void 0 ? void 0 : _a.resolve,
1032
1144
  },
1033
- plugins: [
1034
- viteReactPlugin(),
1035
- extractComponentsConfigPlugin({
1036
- isDev: !!watch,
1037
- globalKey: "componentsMeta",
1038
- fileName: "embeddable-components-meta.js",
1039
- outputDir: ctx.client.buildDir,
1040
- componentFileRegex: EMB_FILE_REGEX,
1041
- searchEntry: "defineComponent",
1042
- }),
1043
- extractComponentsConfigPlugin({
1044
- isDev: !!watch,
1045
- globalKey: "editorsMeta",
1046
- fileName: "embeddable-editors-meta.js",
1047
- outputDir: ctx.client.buildDir,
1048
- componentFileRegex: EMB_FILE_REGEX,
1049
- searchEntry: "defineEditor",
1050
- }),
1051
- validateComponentMetaPlugin(EMB_FILE_REGEX),
1052
- ],
1145
+ plugins,
1053
1146
  build: {
1054
1147
  sourcemap: true,
1055
1148
  watch: watch
@@ -1065,7 +1158,6 @@ async function runViteBuild(ctx, watch = null) {
1065
1158
  ...ctx.client.rollupOptions,
1066
1159
  output: {
1067
1160
  sourcemapPathTransform: (relativeSourcePath, sourcemapPath) => {
1068
- // will replace relative paths with absolute paths
1069
1161
  return path.resolve(path.dirname(sourcemapPath), relativeSourcePath);
1070
1162
  },
1071
1163
  },
@@ -1081,14 +1173,60 @@ async function runViteBuild(ctx, watch = null) {
1081
1173
  define: {
1082
1174
  "process.env.NODE_ENV": `${watch ? '"development"' : '"production"'}`,
1083
1175
  },
1084
- });
1176
+ };
1177
+ }
1178
+ async function calculateBundleHash(ctx) {
1179
+ const componentBuildDir = path.resolve(ctx.client.buildDir, ctx["sdk-react"].outputOptions.buildName);
1180
+ const files = await findFiles(componentBuildDir, /\.(js|ts|tsx|jsx|css)$/);
1181
+ let contentString = "";
1182
+ for (const [, filePath] of files) {
1183
+ const content = await fs$2.readFile(filePath, "utf8");
1184
+ contentString += content;
1185
+ }
1186
+ ctx.client.bundleHash = getContentHash(contentString);
1187
+ }
1188
+ async function runViteBuild(ctx, watch = null) {
1189
+ // Step 1: Initial build without extractComponentsConfigPlugin
1190
+ await vite.build(getViteConfig(ctx, watch, [
1191
+ viteReactPlugin(),
1192
+ validateComponentMetaPlugin(EMB_FILE_REGEX),
1193
+ ]));
1194
+ // Step 2: Calculate bundleHash in production mode
1195
+ if (!watch) {
1196
+ await calculateBundleHash(ctx);
1197
+ }
1198
+ const { externalComponents, externalEditors } = await findExternalComponents(ctx);
1199
+ // Step 3: Final build with extractComponentsConfigPlugin
1200
+ return await vite.build(getViteConfig(ctx, watch, [
1201
+ viteReactPlugin(),
1202
+ extractComponentsConfigPlugin({
1203
+ isDev: !!watch,
1204
+ globalKey: "componentsMeta",
1205
+ fileName: "embeddable-components-meta.js",
1206
+ outputDir: ctx.client.buildDir,
1207
+ componentFileRegex: EMB_FILE_REGEX,
1208
+ searchEntry: "defineComponent",
1209
+ useBundleHash: !watch,
1210
+ ctx,
1211
+ externalComponents: externalComponents,
1212
+ }),
1213
+ extractComponentsConfigPlugin({
1214
+ isDev: !!watch,
1215
+ globalKey: "editorsMeta",
1216
+ fileName: "embeddable-editors-meta.js",
1217
+ outputDir: ctx.client.buildDir,
1218
+ componentFileRegex: EMB_FILE_REGEX,
1219
+ searchEntry: "defineEditor",
1220
+ useBundleHash: !watch,
1221
+ ctx,
1222
+ externalComponents: externalEditors,
1223
+ }),
1224
+ validateComponentMetaPlugin(EMB_FILE_REGEX),
1225
+ ]));
1085
1226
  }
1086
1227
  async function runViteWatch(ctx) {
1087
1228
  const watch = {
1088
- chokidar: {
1089
- ignored: ["**/node_modules/**", /.*\.emb-temp.js$/, /.*\.cube.js$/],
1090
- },
1091
- };
1229
+ };
1092
1230
  return (await runViteBuild(ctx, watch));
1093
1231
  }
1094
1232
  const IMPORT_REPLACE_TOKEN = "{{LAZY_IMPORTS}}";
@@ -1105,10 +1243,14 @@ function getRelativeFileNameForImport(ctx, fileName) {
1105
1243
  // but for imports it must be '.src/something/something'
1106
1244
  .replaceAll("\\", "/")}`;
1107
1245
  }
1108
- async function prepareEntrypoint(ctx, filesList) {
1109
- const imports = filesList
1246
+ async function prepareEntrypoint(ctx, filesList, additionalComponents) {
1247
+ const additionalComponentsImports = getAdditionalEntryPointImports(additionalComponents);
1248
+ const repositoryImports = filesList
1110
1249
  .map(([fileName, filePath]) => `\t${fileName}: React.lazy(() => import('${getRelativeFileNameForImport(ctx, filePath)}'))`)
1111
1250
  .join(",\n");
1251
+ const imports = [additionalComponentsImports, repositoryImports]
1252
+ .filter(Boolean)
1253
+ .join(",\n");
1112
1254
  let errorBoundaryImport = "";
1113
1255
  let errorFallbackComponent = "null";
1114
1256
  if (ctx.client.errorFallbackComponent) {
@@ -1134,12 +1276,262 @@ async function prepareEntrypoint(ctx, filesList) {
1134
1276
  .replace(ADDITIONAL_CONTENT_BEGIN_TOKEN, additionalContentBegin.join("\n"))
1135
1277
  .replace(ADDITIONAL_CONTENT_END_TOKEN, additionalContentEnd.join("\n")));
1136
1278
  }
1279
+ const findExternalComponents = async (ctx) => {
1280
+ var _a;
1281
+ const componentLibraries = ctx.client.componentLibraries || [];
1282
+ const externalComponents = [];
1283
+ const externalEditors = [];
1284
+ for (const componentLibrary of componentLibraries) {
1285
+ const { libraryName} = getComponentLibraryConfig(componentLibrary);
1286
+ try {
1287
+ const libMeta = await getComponentLibraryMeta(ctx, componentLibrary);
1288
+ if (libMeta.plugin !== "react") {
1289
+ continue;
1290
+ }
1291
+ const components = libMeta.components.map((component) => {
1292
+ return [
1293
+ component,
1294
+ path.resolve(ctx.client.rootDir, "node_modules", libraryName, "dist", `${component}.js`),
1295
+ ];
1296
+ });
1297
+ const editors = ((_a = libMeta.editors) === null || _a === void 0 ? void 0 : _a.map((component) => {
1298
+ return [
1299
+ component,
1300
+ path.resolve(ctx.client.rootDir, "node_modules", libraryName, "dist", `${component}.js`),
1301
+ ];
1302
+ })) || [];
1303
+ externalComponents.push(...components);
1304
+ externalEditors.push(...editors);
1305
+ }
1306
+ catch (e) {
1307
+ console.error(`Can't load component library: ${libraryName}`, e);
1308
+ throw e;
1309
+ }
1310
+ }
1311
+ return { externalComponents, externalEditors };
1312
+ };
1313
+ const getAdditionalComponents$1 = async (ctx) => {
1314
+ const componentLibraries = ctx.client.componentLibraries || [];
1315
+ let additionalComponents = {};
1316
+ for (const componentLibrary of componentLibraries) {
1317
+ const { libraryName} = getComponentLibraryConfig(componentLibrary);
1318
+ try {
1319
+ const libMeta = await getComponentLibraryMeta(ctx, componentLibrary);
1320
+ if (libMeta.plugin !== "react") {
1321
+ continue;
1322
+ }
1323
+ additionalComponents[libraryName] = [
1324
+ ...libMeta.components,
1325
+ ...libMeta.editors,
1326
+ ];
1327
+ }
1328
+ catch (e) {
1329
+ console.error(`Can't load component library: ${libraryName}`, e);
1330
+ throw e;
1331
+ }
1332
+ }
1333
+ return additionalComponents;
1334
+ };
1335
+ const getAdditionalEntryPointImports = (additionalComponents) => {
1336
+ return Object.entries(additionalComponents)
1337
+ .map(([library, components]) => {
1338
+ return components
1339
+ .map((component) => {
1340
+ return `\t${component}: React.lazy(() => import('${library}/dist/${component}'))`;
1341
+ })
1342
+ .join(",\n");
1343
+ })
1344
+ .join(",\n");
1345
+ };
1346
+
1347
+ const oraP = import('ora');
1348
+ async function buildPackage$1(ctx) {
1349
+ var _a;
1350
+ const ora = (await oraP).default;
1351
+ const progress = ora("React: building library...").start();
1352
+ await prepareComponentLibraries(ctx);
1353
+ await usageValidator(ctx.client.srcDir, false);
1354
+ const filesList = await findFiles(ctx.client.srcDir, EMB_FILE_REGEX);
1355
+ const additionalComponents = await getAdditionalComponents(ctx);
1356
+ const errors = validateComponentDuplicates(filesList, additionalComponents.allAdditionalComponents, ora);
1357
+ if (errors.length) {
1358
+ process.exit(1);
1359
+ }
1360
+ const inputEntries = Object.fromEntries(filesList);
1361
+ const indexFiles = ["index.ts", "index.js"]
1362
+ .map((file) => path.resolve(ctx.client.srcDir, file))
1363
+ .filter(fs$1.existsSync);
1364
+ const tsConfigClientPath = path.resolve(ctx.client.rootDir, "tsconfig.json");
1365
+ const tsconfigPath = existsSync(tsConfigClientPath)
1366
+ ? tsConfigClientPath
1367
+ : undefined;
1368
+ const componentFiles = {};
1369
+ const editorFiles = {};
1370
+ if (indexFiles.length > 0) {
1371
+ inputEntries["index"] = indexFiles[0];
1372
+ }
1373
+ if (Object.keys(inputEntries).length === 0) {
1374
+ progress.fail("No components found");
1375
+ return;
1376
+ }
1377
+ Object.entries(additionalComponents.allAdditionalComponents).forEach(([libraryName, components]) => {
1378
+ components.forEach((component) => {
1379
+ inputEntries[component] = path.resolve(ctx.client.rootDir, "node_modules", libraryName, "dist", `${component}.js`);
1380
+ });
1381
+ });
1382
+ await vite.build({
1383
+ logLevel: "error",
1384
+ resolve: {
1385
+ extensions: [".ts", ".tsx", ".js", ".jsx", ".json"],
1386
+ ...(_a = ctx.client.viteConfig) === null || _a === void 0 ? void 0 : _a.resolve,
1387
+ },
1388
+ plugins: [
1389
+ viteReactPlugin(),
1390
+ validateComponentMetaPlugin(EMB_FILE_REGEX),
1391
+ dts({
1392
+ tsconfigPath,
1393
+ compilerOptions: {
1394
+ rootDir: ctx.client.srcDir,
1395
+ },
1396
+ exclude: ["**/node_modules/**", "**/*.emb.{ts,js}"],
1397
+ }),
1398
+ {
1399
+ name: "generate-embeddable-components-json",
1400
+ generateBundle(_, __) {
1401
+ const libMeta = {
1402
+ components: Object.keys(componentFiles).concat(additionalComponents.components),
1403
+ editors: Object.keys(editorFiles).concat(additionalComponents.editors),
1404
+ plugin: "react",
1405
+ };
1406
+ const jsonContent = JSON.stringify(libMeta, null, 2);
1407
+ this.emitFile({
1408
+ type: "asset",
1409
+ fileName: EXTERNAL_LIBRARY_META_FILE_NAME,
1410
+ source: jsonContent,
1411
+ });
1412
+ },
1413
+ },
1414
+ groupComponents(componentFiles, editorFiles),
1415
+ ],
1416
+ build: {
1417
+ sourcemap: true,
1418
+ minify: true,
1419
+ emptyOutDir: false,
1420
+ rollupOptions: {
1421
+ ...ctx.client.rollupOptions,
1422
+ external: ["react", "react-dom", "@embeddable.com/react"],
1423
+ },
1424
+ lib: {
1425
+ entry: inputEntries,
1426
+ formats: ["es"],
1427
+ },
1428
+ },
1429
+ define: {
1430
+ "process.env.NODE_ENV": '"production"',
1431
+ },
1432
+ });
1433
+ progress.succeed("Building React library completed");
1434
+ }
1435
+ const groupComponents = (components, editors) => ({
1436
+ name: "group-components",
1437
+ moduleParsed(moduleInfo) {
1438
+ if (!moduleInfo ||
1439
+ !moduleInfo.ast ||
1440
+ !moduleInfo.id ||
1441
+ !moduleInfo.id.match(EMB_FILE_REGEX))
1442
+ return;
1443
+ try {
1444
+ moduleInfo.ast.body.forEach((node) => {
1445
+ if (node.type === "ExportDefaultDeclaration") {
1446
+ const calleeName = node.declaration.type === "CallExpression" &&
1447
+ node.declaration.callee.type === "Identifier"
1448
+ ? node.declaration.callee.name
1449
+ : null;
1450
+ const isTs = moduleInfo.id.endsWith(".ts");
1451
+ const basename = path.basename(moduleInfo.id, `.emb.${isTs ? "ts" : "js"}`);
1452
+ if (calleeName === "defineComponent") {
1453
+ components[basename] = moduleInfo.id;
1454
+ }
1455
+ else if (calleeName === "defineEditor") {
1456
+ editors[basename] = moduleInfo.id;
1457
+ }
1458
+ }
1459
+ });
1460
+ }
1461
+ catch (error) {
1462
+ console.warn(`Failed to process AST for module: ${moduleInfo.id}`, error);
1463
+ }
1464
+ },
1465
+ });
1466
+ const prepareComponentLibraries = async (ctx) => {
1467
+ const componentLibraries = ctx.client.componentLibraries;
1468
+ for (const componentLibrary of componentLibraries) {
1469
+ const { libraryName } = getComponentLibraryConfig(componentLibrary);
1470
+ const libPath = path.resolve(ctx.client.rootDir, "node_modules", libraryName, "dist");
1471
+ const libMeta = await getComponentLibraryMeta(ctx, componentLibrary);
1472
+ if (libMeta.plugin !== "react") {
1473
+ continue;
1474
+ }
1475
+ copyFilesWithExtensions(libPath, ctx.client.buildDir, [".css"], (file) => !file.startsWith("embeddable-types"), (file) => file.endsWith(".css")
1476
+ ? `${libraryName.replace(/[@/]/g, "_")}-${file}`
1477
+ : file);
1478
+ }
1479
+ };
1480
+ function copyFilesWithExtensions(srcDir, destDir, exts, filter, nameMapper) {
1481
+ if (!fs$1.existsSync(destDir)) {
1482
+ fs$1.mkdirSync(destDir, { recursive: true });
1483
+ }
1484
+ const entries = fs$1.readdirSync(srcDir, { withFileTypes: true });
1485
+ for (const entry of entries) {
1486
+ const srcPath = path.join(srcDir, entry.name);
1487
+ const destPath = path.join(destDir, nameMapper(entry.name));
1488
+ if (entry.isDirectory()) {
1489
+ copyFilesWithExtensions(srcPath, destPath, exts, filter, nameMapper);
1490
+ }
1491
+ else if (entry.isFile() &&
1492
+ exts.includes(path.extname(entry.name)) &&
1493
+ (!filter || filter(entry.name))) {
1494
+ fs$1.copyFileSync(srcPath, destPath);
1495
+ }
1496
+ }
1497
+ }
1498
+ const getAdditionalComponents = async (ctx) => {
1499
+ const componentLibraries = ctx.client.componentLibraries || [];
1500
+ const allAdditionalComponents = {};
1501
+ const components = [];
1502
+ const editors = [];
1503
+ for (const componentLibrary of componentLibraries) {
1504
+ const { libraryName } = getComponentLibraryConfig(componentLibrary);
1505
+ try {
1506
+ const libMeta = await getComponentLibraryMeta(ctx, componentLibrary);
1507
+ if (libMeta.plugin !== "react") {
1508
+ continue;
1509
+ }
1510
+ allAdditionalComponents[libraryName] = [
1511
+ ...libMeta.components,
1512
+ ...libMeta.editors,
1513
+ ];
1514
+ components.push(...libMeta.components);
1515
+ editors.push(...libMeta.editors);
1516
+ }
1517
+ catch (e) {
1518
+ console.error(`Can't load component library: ${libraryName}`, e);
1519
+ throw e;
1520
+ }
1521
+ }
1522
+ return { components, editors, allAdditionalComponents };
1523
+ };
1137
1524
 
1138
1525
  var build = async (ctx) => {
1139
1526
  const __dirname = import.meta.dirname;
1140
1527
  createContext(path$1.resolve(__dirname, ".."), ctx);
1141
1528
  return generate(ctx);
1142
1529
  };
1530
+ const buildPackage = async (ctx) => {
1531
+ const __dirname = import.meta.dirname;
1532
+ createContext(path$1.resolve(__dirname, ".."), ctx);
1533
+ return buildPackage$1(ctx);
1534
+ };
1143
1535
 
1144
1536
  var cleanup = async (ctx) => {
1145
1537
  await rm(resolve(ctx.client.buildDir, ctx["sdk-react"].outputOptions.componentsEntryPointFilename));
@@ -1150,6 +1542,7 @@ var index = () => {
1150
1542
  pluginName: "sdk-react",
1151
1543
  validate: async () => { },
1152
1544
  build,
1545
+ buildPackage,
1153
1546
  cleanup,
1154
1547
  };
1155
1548
  };