@ethisyscore/vite-plugin 1.16.0 → 1.17.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/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'fs';
1
+ import { existsSync, readFileSync, rmSync, mkdirSync, writeFileSync } from 'fs';
2
2
  import { isAbsolute, resolve, sep, normalize, dirname } from 'path';
3
3
  import { KNOWN_PRIMITIVES, KNOWN_OPERATORS, KNOWN_RULE_KINDS, SduiNode, ReactiveRule, IframeSandboxPageDeclaration, AssetDigest } from '@ethisyscore/protocol';
4
4
  import { createHash } from 'crypto';
@@ -122,7 +122,7 @@ function ethisysContractAPlugin(options = {}) {
122
122
  manifestAbsPath = isAbsolute(manifestRel) ? manifestRel : resolve(resolvedRoot, manifestRel);
123
123
  return resolvedRoot;
124
124
  }
125
- function readManifest2() {
125
+ function readManifest3() {
126
126
  resolveRoot();
127
127
  if (!existsSync(manifestAbsPath)) {
128
128
  return null;
@@ -139,7 +139,7 @@ function ethisysContractAPlugin(options = {}) {
139
139
  function validate() {
140
140
  validatedResources = [];
141
141
  resourcePayloads.clear();
142
- const manifest = readManifest2();
142
+ const manifest = readManifest3();
143
143
  if (manifest === null) {
144
144
  return;
145
145
  }
@@ -385,7 +385,7 @@ function ethisysContractBPlugin(options = {}) {
385
385
  manifestAbsPath = isAbsolute(manifestRel) ? manifestRel : resolve(resolvedRoot, manifestRel);
386
386
  return resolvedRoot;
387
387
  }
388
- function readManifest2() {
388
+ function readManifest3() {
389
389
  resolveRoot();
390
390
  if (!existsSync(manifestAbsPath)) {
391
391
  return null;
@@ -402,7 +402,7 @@ function ethisysContractBPlugin(options = {}) {
402
402
  function validate() {
403
403
  workerEntryAbs = null;
404
404
  workerEntryRel = null;
405
- const manifest = readManifest2();
405
+ const manifest = readManifest3();
406
406
  if (manifest === null) {
407
407
  return;
408
408
  }
@@ -633,7 +633,7 @@ function ethisysPlatformReactPlugin(options = {}) {
633
633
  manifestAbsPath = isAbsolute(manifestRel) ? manifestRel : resolve(resolvedRoot, manifestRel);
634
634
  return resolvedRoot;
635
635
  }
636
- function readManifest2() {
636
+ function readManifest3() {
637
637
  resolveRoot();
638
638
  if (!existsSync(manifestAbsPath)) {
639
639
  return null;
@@ -649,7 +649,7 @@ function ethisysPlatformReactPlugin(options = {}) {
649
649
  }
650
650
  function validate() {
651
651
  pages = [];
652
- const manifest = readManifest2();
652
+ const manifest = readManifest3();
653
653
  if (manifest === null) {
654
654
  return;
655
655
  }
@@ -914,13 +914,231 @@ function parsePlatformReactPages(manifestPath, options = {}) {
914
914
  }
915
915
  return result;
916
916
  }
917
+ var PLATFORM_REACT_EXTERNALS = [
918
+ "react",
919
+ "react/jsx-runtime",
920
+ "react-dom",
921
+ "@mui/material",
922
+ "@mui/icons-material",
923
+ "@emotion/react",
924
+ "@emotion/styled",
925
+ "date-fns",
926
+ "@ethisyscore/components-react",
927
+ "@ethisyscore/extension-runtime",
928
+ "@ethisyscore/extension-runtime/plugin"
929
+ ];
930
+ var PLATFORM_REACT_DEDUPE = [
931
+ "@tanstack/react-query",
932
+ "react",
933
+ "react-dom",
934
+ "@ethisyscore/extension-runtime"
935
+ ];
936
+ var DEFAULT_OUT_DIR = "dist";
937
+ var DEFAULT_OUTPUT_PREFIX = "platform-react";
938
+ var DEFAULT_DEFINE_PLUGIN_PAGE = "@/app/definePluginPage";
939
+ var DEFAULT_SRC_DIR = "src";
940
+ var DEFAULT_ALIAS_PREFIX = "@";
941
+ var SUMMARY_FILENAME = "platform-react-pages.json";
942
+ var DIGEST_MAP_FILENAME = "platform-react-digest-map.json";
943
+ function rewriteAliasedExternalImports() {
944
+ return {
945
+ name: "rewrite-aliased-external-imports",
946
+ renderChunk(code) {
947
+ let counter = 0;
948
+ let changed = false;
949
+ const out = code.replace(
950
+ // Optional default binding (`import Foo, { … }`) then the named braces.
951
+ /\bimport\s+(?:([\w$]+)\s*,\s*)?\{([^{}]*)\}\s*from\s*("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')\s*;?/g,
952
+ (full, def, specs, mod) => {
953
+ if (!/\sas\s/.test(specs)) return full;
954
+ changed = true;
955
+ const ns = `__ns_imp_${counter++}`;
956
+ const decls = specs.split(",").map((s) => s.trim()).filter(Boolean).map((s) => {
957
+ const [imported, local] = s.split(/\s+as\s+/).map((t) => t.trim());
958
+ return `${local ?? imported} = ${ns}.${imported}`;
959
+ }).join(", ");
960
+ const defPart = def ? `import ${def} from ${mod}; ` : "";
961
+ return `${defPart}import * as ${ns} from ${mod}; const ${decls};`;
962
+ }
963
+ );
964
+ return changed ? { code: out, map: null } : null;
965
+ }
966
+ };
967
+ }
968
+ function virtualPageEntry(page, config) {
969
+ const VIRTUAL_ID = `\0virtual:surface/${page.id}`;
970
+ const views = page.views ?? {};
971
+ const names = Object.keys(views);
972
+ const viewImports = names.map((n) => `import { ${n} } from ${JSON.stringify(config.toAlias(views[n]))};`).join("\n");
973
+ const src = `import Page from ${JSON.stringify(config.toAlias(page.moduleSpecifier))};
974
+ ${viewImports}
975
+ import { definePluginPage } from ${JSON.stringify(config.definePluginPageSpecifier)};
976
+ export default definePluginPage(Page, { ${names.join(", ")} });
977
+ `;
978
+ return {
979
+ id: VIRTUAL_ID,
980
+ plugin: {
981
+ name: `virtual-surface-${page.id}`,
982
+ resolveId: (id) => id === VIRTUAL_ID ? VIRTUAL_ID : null,
983
+ load: (id) => id === VIRTUAL_ID ? src : null
984
+ }
985
+ };
986
+ }
987
+ function defaultWriteFile(path, contents) {
988
+ mkdirSync(dirname(path), { recursive: true });
989
+ writeFileSync(path, contents);
990
+ }
991
+ function escapeRegExp(s) {
992
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
993
+ }
994
+ function readManifest(options, root) {
995
+ if (options.manifest !== void 0) {
996
+ return options.manifest;
997
+ }
998
+ const rel = options.manifestPath ?? "feature.manifest.json";
999
+ const abs = isAbsolute(rel) ? rel : resolve(root, rel);
1000
+ if (!existsSync(abs)) {
1001
+ return null;
1002
+ }
1003
+ const raw = readFileSync(abs, "utf-8");
1004
+ try {
1005
+ return JSON.parse(raw);
1006
+ } catch (e) {
1007
+ throw new Error(
1008
+ `[ethisys-platform-react] Failed to parse manifest at "${abs}": ${e.message}`
1009
+ );
1010
+ }
1011
+ }
1012
+ function makeDefaultBuild(viteBuild) {
1013
+ return async (ctx) => {
1014
+ const build = viteBuild ?? (await import('vite')).build;
1015
+ await build({
1016
+ root: ctx.root,
1017
+ configFile: false,
1018
+ plugins: [ctx.surfacePlugin, ...ctx.plugins, rewriteAliasedExternalImports()],
1019
+ resolve: {
1020
+ dedupe: [...ctx.dedupe],
1021
+ alias: ctx.alias
1022
+ },
1023
+ build: {
1024
+ target: ctx.target,
1025
+ outDir: ctx.outDir,
1026
+ emptyOutDir: false,
1027
+ assetsDir: "",
1028
+ minify: ctx.minify,
1029
+ sourcemap: ctx.sourcemap,
1030
+ rollupOptions: {
1031
+ input: { [ctx.pageId]: ctx.entryId },
1032
+ preserveEntrySignatures: "strict",
1033
+ external: [...ctx.external],
1034
+ output: {
1035
+ format: "es",
1036
+ inlineDynamicImports: true,
1037
+ entryFileNames: `${ctx.outputPrefix}/[name].js`,
1038
+ chunkFileNames: `${ctx.outputPrefix}/[name]-[hash].js`,
1039
+ assetFileNames: `${ctx.outputPrefix}/[name][extname]`
1040
+ }
1041
+ }
1042
+ },
1043
+ logLevel: "warn"
1044
+ });
1045
+ };
1046
+ }
1047
+ async function buildPlatformReactPages(options = {}) {
1048
+ const root = options.root ?? process.cwd();
1049
+ const logger = options.logger ?? console;
1050
+ const manifest = readManifest(options, root);
1051
+ const declared = manifest?.ui?.platformReactPages;
1052
+ if (!Array.isArray(declared) || declared.length === 0) {
1053
+ logger.warn("[build-pages] no platformReactPages declared \u2014 nothing to build");
1054
+ return { pages: [], digests: [], summaryPath: null, digestMapPath: null };
1055
+ }
1056
+ const seen = /* @__PURE__ */ new Set();
1057
+ const pages = declared.map((raw, i) => {
1058
+ const decl = raw;
1059
+ if (typeof decl?.id !== "string" || decl.id.length === 0) {
1060
+ throw new Error(`[build-pages] ui.platformReactPages[${i}].id is required (non-empty string).`);
1061
+ }
1062
+ if (seen.has(decl.id)) {
1063
+ throw new Error(`[build-pages] Duplicate page id "${decl.id}".`);
1064
+ }
1065
+ seen.add(decl.id);
1066
+ if (typeof decl.moduleSpecifier !== "string" || decl.moduleSpecifier.length === 0) {
1067
+ throw new Error(`[build-pages] surface "${decl.id}" has no moduleSpecifier in the manifest.`);
1068
+ }
1069
+ return decl;
1070
+ });
1071
+ const outDir = options.outDir ?? DEFAULT_OUT_DIR;
1072
+ const outDirAbs = isAbsolute(outDir) ? outDir : resolve(root, outDir);
1073
+ const outputPrefix = (options.outputPrefix ?? DEFAULT_OUTPUT_PREFIX).replace(/^\/+|\/+$/g, "");
1074
+ const outputPrefixDir = resolve(outDirAbs, outputPrefix);
1075
+ const external = options.external ?? PLATFORM_REACT_EXTERNALS;
1076
+ const dedupe = options.dedupe ?? PLATFORM_REACT_DEDUPE;
1077
+ const alias = options.alias ?? [];
1078
+ const plugins = options.plugins ?? [];
1079
+ const definePluginPageSpecifier = options.definePluginPageSpecifier ?? DEFAULT_DEFINE_PLUGIN_PAGE;
1080
+ const srcDir = options.srcDir ?? DEFAULT_SRC_DIR;
1081
+ const aliasPrefix = options.aliasPrefix ?? DEFAULT_ALIAS_PREFIX;
1082
+ const srcRe = new RegExp(`^${escapeRegExp(srcDir)}/`);
1083
+ const toAlias = (p) => `${aliasPrefix}/${p.replace(srcRe, "")}`;
1084
+ const write = options.writeFile ?? defaultWriteFile;
1085
+ const read = options.readFile ?? ((p) => readFileSync(p, "utf-8"));
1086
+ const runBuild = options.build ?? makeDefaultBuild(options.viteBuild);
1087
+ if (options.clean ?? true) {
1088
+ if (existsSync(outDirAbs)) {
1089
+ rmSync(outDirAbs, { recursive: true, force: true });
1090
+ }
1091
+ mkdirSync(outputPrefixDir, { recursive: true });
1092
+ }
1093
+ for (const page of pages) {
1094
+ const { id: entryId, plugin: surfacePlugin } = virtualPageEntry(page, {
1095
+ definePluginPageSpecifier,
1096
+ toAlias
1097
+ });
1098
+ logger.log(`[build-pages] ${page.id} \u2190 ${page.moduleSpecifier}`);
1099
+ await runBuild({
1100
+ pageId: page.id,
1101
+ entryId,
1102
+ surfacePlugin,
1103
+ root,
1104
+ outDir: outDirAbs,
1105
+ outputPrefix,
1106
+ external,
1107
+ dedupe,
1108
+ alias,
1109
+ plugins,
1110
+ target: options.target ?? "es2022",
1111
+ minify: options.minify ?? false,
1112
+ sourcemap: options.sourcemap ?? true
1113
+ });
1114
+ }
1115
+ const summaryPages = pages.map((p) => ({
1116
+ id: p.id,
1117
+ exportName: p.exportName ?? "default",
1118
+ title: p.title ?? null,
1119
+ bundlePath: `${outputPrefix}/${p.id}.js`,
1120
+ source: p.moduleSpecifier
1121
+ }));
1122
+ const summaryPath = resolve(outputPrefixDir, SUMMARY_FILENAME);
1123
+ write(summaryPath, JSON.stringify({ pages: summaryPages }, null, 2));
1124
+ const digests = pages.map((p) => `${outputPrefix}/${p.id}.js`).sort().map((relPath) => {
1125
+ const code = read(resolve(outDirAbs, relPath));
1126
+ return { path: relPath, sha256: createHash("sha256").update(code, "utf8").digest("hex") };
1127
+ });
1128
+ const digestMapPath = resolve(outputPrefixDir, DIGEST_MAP_FILENAME);
1129
+ write(digestMapPath, JSON.stringify({ digests }, null, 2));
1130
+ logger.log(
1131
+ `[build-pages] emitted ${pages.length} page(s) + summary + digest map (${digests.length} digests)`
1132
+ );
1133
+ return { pages: summaryPages, digests, summaryPath, digestMapPath };
1134
+ }
917
1135
  var DEFAULT_MANIFEST = "feature.manifest.json";
918
1136
  var DEFAULT_OUTPUT_DIR = "dist/iframe-sandbox";
919
- var DIGEST_MAP_FILENAME = "iframe-sandbox-digest-map.json";
1137
+ var DIGEST_MAP_FILENAME2 = "iframe-sandbox-digest-map.json";
920
1138
  function slash3(p) {
921
1139
  return sep === "\\" ? p.replace(/\\/g, "/") : p;
922
1140
  }
923
- function defaultWriteFile(path, contents) {
1141
+ function defaultWriteFile2(path, contents) {
924
1142
  mkdirSync(dirname(path), { recursive: true });
925
1143
  writeFileSync(path, contents);
926
1144
  }
@@ -944,7 +1162,7 @@ function digestOf(item) {
944
1162
  const bytes = item.type === "chunk" ? item.code : item.source;
945
1163
  return createHash("sha256").update(bytes).digest("hex");
946
1164
  }
947
- function readManifest(options, root) {
1165
+ function readManifest2(options, root) {
948
1166
  if (options.manifest !== void 0) {
949
1167
  return options.manifest;
950
1168
  }
@@ -962,7 +1180,7 @@ function readManifest(options, root) {
962
1180
  }
963
1181
  async function buildIframeSandboxPages(options = {}) {
964
1182
  const root = options.root ?? process.cwd();
965
- const manifest = readManifest(options, root);
1183
+ const manifest = readManifest2(options, root);
966
1184
  const declared = manifest?.ui?.iframeSandboxPages;
967
1185
  if (!Array.isArray(declared) || declared.length === 0) {
968
1186
  return { digests: [], digestMapPath: null };
@@ -984,7 +1202,7 @@ async function buildIframeSandboxPages(options = {}) {
984
1202
  seen.add(p.id);
985
1203
  }
986
1204
  const build = options.build ?? defaultBuild;
987
- const write = options.writeFile ?? defaultWriteFile;
1205
+ const write = options.writeFile ?? defaultWriteFile2;
988
1206
  const outputDir = options.outputDir ?? DEFAULT_OUTPUT_DIR;
989
1207
  const outDirAbs = isAbsolute(outputDir) ? outputDir : resolve(root, outputDir);
990
1208
  const digests = [];
@@ -1002,7 +1220,7 @@ async function buildIframeSandboxPages(options = {}) {
1002
1220
  digests.push(entry);
1003
1221
  }
1004
1222
  }
1005
- const digestMapPath = resolve(outDirAbs, DIGEST_MAP_FILENAME);
1223
+ const digestMapPath = resolve(outDirAbs, DIGEST_MAP_FILENAME2);
1006
1224
  write(slash3(digestMapPath), JSON.stringify({ digests }, null, 2));
1007
1225
  return { digests, digestMapPath };
1008
1226
  }
@@ -1082,7 +1300,7 @@ function ethisysManifestPlugin(options = {}) {
1082
1300
  </body>
1083
1301
  </html>`;
1084
1302
  }
1085
- function readManifest2() {
1303
+ function readManifest3() {
1086
1304
  if (!existsSync(manifestAbsPath)) {
1087
1305
  return [];
1088
1306
  }
@@ -1134,7 +1352,7 @@ function ethisysManifestPlugin(options = {}) {
1134
1352
  config(config, { command }) {
1135
1353
  rootDir = config.root ?? process.cwd();
1136
1354
  manifestAbsPath = resolve(rootDir, manifestRelPath);
1137
- entries = readManifest2();
1355
+ entries = readManifest3();
1138
1356
  if (entries.length === 0) {
1139
1357
  return;
1140
1358
  }
@@ -1215,7 +1433,7 @@ function ethisysManifestPlugin(options = {}) {
1215
1433
  handleHotUpdate({ file, server }) {
1216
1434
  if (slash4(file) === slash4(manifestAbsPath)) {
1217
1435
  try {
1218
- entries = readManifest2();
1436
+ entries = readManifest3();
1219
1437
  validateEntries();
1220
1438
  htmlCache.clear();
1221
1439
  } catch (e) {
@@ -1252,6 +1470,6 @@ function ethisysManifestPlugin(options = {}) {
1252
1470
  };
1253
1471
  }
1254
1472
 
1255
- export { CONTRACT_B_IMPORT_MAP_ALLOWLIST, CONTRACT_B_RUNTIME_IMPORTS, CONTRACT_B_SEMANTIC_PRIMITIVES, buildIframeSandboxPages, ethisysContractAPlugin, ethisysContractBPlugin, ethisysIframeSandboxPlugin, ethisysManifestPlugin, ethisysPlatformReactPlugin, parsePlatformReactPages, validateDeclarativeResource, validateReactiveRule };
1473
+ export { CONTRACT_B_IMPORT_MAP_ALLOWLIST, CONTRACT_B_RUNTIME_IMPORTS, CONTRACT_B_SEMANTIC_PRIMITIVES, PLATFORM_REACT_DEDUPE, PLATFORM_REACT_EXTERNALS, buildIframeSandboxPages, buildPlatformReactPages, ethisysContractAPlugin, ethisysContractBPlugin, ethisysIframeSandboxPlugin, ethisysManifestPlugin, ethisysPlatformReactPlugin, parsePlatformReactPages, rewriteAliasedExternalImports, validateDeclarativeResource, validateReactiveRule, virtualPageEntry };
1256
1474
  //# sourceMappingURL=index.js.map
1257
1475
  //# sourceMappingURL=index.js.map