@fluid-app/fluid-cli-portal 0.1.78 → 0.1.79

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.
@@ -1,4 +1,4 @@
1
- import { N as __exportAll } from "./pull-BWnby_pY.mjs";
1
+ import { N as __exportAll } from "./pull-Kx1ncTLF.mjs";
2
2
  //#region src/vite-plugin/backend-dev-plugin.ts
3
3
  var backend_dev_plugin_exports = /* @__PURE__ */ __exportAll({ backendDevPlugin: () => backendDevPlugin });
4
4
  /**
@@ -61,4 +61,4 @@ function serve(res, contentType, body) {
61
61
  //#endregion
62
62
  export { backend_dev_plugin_exports as n, backendDevPlugin as t };
63
63
 
64
- //# sourceMappingURL=backend-dev-plugin-z9IZCHaY.mjs.map
64
+ //# sourceMappingURL=backend-dev-plugin-Dy2Fcdg7.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"backend-dev-plugin-z9IZCHaY.mjs","names":[],"sources":["../src/vite-plugin/backend-dev-plugin.ts"],"sourcesContent":["import type { Plugin } from \"vite\";\n\nexport interface BackendDevPluginOptions {\n /** Entry module path relative to project root. @default \"/src/main.tsx\" */\n entry?: string;\n /** Production chunk filenames to stub as empty ES modules. */\n chunks?: string[];\n}\n\n/**\n * Serves dev-compatible responses at production asset paths so the Rails\n * backend can point `PORTAL_CDN_BASE` at `http://localhost:5173` and get\n * HMR + live source without any template changes.\n *\n * Handles:\n * - `/portal.js` → ESM shim that loads `@vite/client` + the real entry\n * - `/portal.css` → empty (Vite injects CSS via JS in dev)\n * - `/vendor.js`, `/query.js` → empty ES modules (no chunks in dev)\n */\nexport function backendDevPlugin(options?: BackendDevPluginOptions): Plugin {\n const entry = options?.entry ?? \"/src/main.tsx\";\n const chunks = options?.chunks ?? [\"vendor.js\", \"query.js\"];\n\n return {\n name: \"fluid-backend-dev\",\n apply: \"serve\",\n\n // Register BEFORE Vite's SPA fallback so these paths don't\n // get caught by the index.html catch-all.\n configureServer(server) {\n // Idempotency guard: the CLI injects this plugin and a vite.config may\n // also wire it — only register the middleware once.\n const flagged = server as unknown as { __fluidBackendDevWired?: boolean };\n if (flagged.__fluidBackendDevWired) return;\n flagged.__fluidBackendDevWired = true;\n\n server.middlewares.use((req, res, next) => {\n const raw = req.url ?? \"\";\n const qIndex = raw.indexOf(\"?\");\n const url = qIndex === -1 ? raw : raw.slice(0, qIndex);\n\n if (url === \"/portal.js\") {\n serve(\n res,\n \"application/javascript\",\n [\n `import RefreshRuntime from \"/@react-refresh\";`,\n `import \"/@vite/client\";`,\n `RefreshRuntime.injectIntoGlobalHook(window);`,\n `window.$RefreshReg$ = () => {};`,\n `window.$RefreshSig$ = () => (type) => type;`,\n `window.__vite_plugin_react_preamble_installed__ = true;`,\n `await import(\"${entry}\");`,\n ].join(\"\\n\"),\n );\n return;\n }\n\n if (url === \"/portal.css\") {\n serve(res, \"text/css\", \"/* dev: CSS injected via JS */\");\n return;\n }\n\n const chunkName = url.startsWith(\"/\") ? url.slice(1) : url;\n if (chunks.includes(chunkName)) {\n serve(res, \"application/javascript\", \"export {};\");\n return;\n }\n\n next();\n });\n },\n };\n}\n\nfunction serve(\n res: import(\"http\").ServerResponse,\n contentType: string,\n body: string,\n) {\n res.setHeader(\"Content-Type\", `${contentType}; charset=utf-8`);\n res.setHeader(\"Cache-Control\", \"no-store\");\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n res.statusCode = 200;\n res.end(body);\n}\n"],"mappings":";;;;;;;;;;;;;AAmBA,SAAgB,iBAAiB,SAA2C;CAC1E,MAAM,QAAQ,SAAS,SAAS;CAChC,MAAM,SAAS,SAAS,UAAU,CAAC,aAAa,WAAW;AAE3D,QAAO;EACL,MAAM;EACN,OAAO;EAIP,gBAAgB,QAAQ;GAGtB,MAAM,UAAU;AAChB,OAAI,QAAQ,uBAAwB;AACpC,WAAQ,yBAAyB;AAEjC,UAAO,YAAY,KAAK,KAAK,KAAK,SAAS;IACzC,MAAM,MAAM,IAAI,OAAO;IACvB,MAAM,SAAS,IAAI,QAAQ,IAAI;IAC/B,MAAM,MAAM,WAAW,KAAK,MAAM,IAAI,MAAM,GAAG,OAAO;AAEtD,QAAI,QAAQ,cAAc;AACxB,WACE,KACA,0BACA;MACE;MACA;MACA;MACA;MACA;MACA;MACA,iBAAiB,MAAM;MACxB,CAAC,KAAK,KAAK,CACb;AACD;;AAGF,QAAI,QAAQ,eAAe;AACzB,WAAM,KAAK,YAAY,iCAAiC;AACxD;;IAGF,MAAM,YAAY,IAAI,WAAW,IAAI,GAAG,IAAI,MAAM,EAAE,GAAG;AACvD,QAAI,OAAO,SAAS,UAAU,EAAE;AAC9B,WAAM,KAAK,0BAA0B,aAAa;AAClD;;AAGF,UAAM;KACN;;EAEL;;AAGH,SAAS,MACP,KACA,aACA,MACA;AACA,KAAI,UAAU,gBAAgB,GAAG,YAAY,iBAAiB;AAC9D,KAAI,UAAU,iBAAiB,WAAW;AAC1C,KAAI,UAAU,+BAA+B,IAAI;AACjD,KAAI,aAAa;AACjB,KAAI,IAAI,KAAK"}
1
+ {"version":3,"file":"backend-dev-plugin-Dy2Fcdg7.mjs","names":[],"sources":["../src/vite-plugin/backend-dev-plugin.ts"],"sourcesContent":["import type { Plugin } from \"vite\";\n\nexport interface BackendDevPluginOptions {\n /** Entry module path relative to project root. @default \"/src/main.tsx\" */\n entry?: string;\n /** Production chunk filenames to stub as empty ES modules. */\n chunks?: string[];\n}\n\n/**\n * Serves dev-compatible responses at production asset paths so the Rails\n * backend can point `PORTAL_CDN_BASE` at `http://localhost:5173` and get\n * HMR + live source without any template changes.\n *\n * Handles:\n * - `/portal.js` → ESM shim that loads `@vite/client` + the real entry\n * - `/portal.css` → empty (Vite injects CSS via JS in dev)\n * - `/vendor.js`, `/query.js` → empty ES modules (no chunks in dev)\n */\nexport function backendDevPlugin(options?: BackendDevPluginOptions): Plugin {\n const entry = options?.entry ?? \"/src/main.tsx\";\n const chunks = options?.chunks ?? [\"vendor.js\", \"query.js\"];\n\n return {\n name: \"fluid-backend-dev\",\n apply: \"serve\",\n\n // Register BEFORE Vite's SPA fallback so these paths don't\n // get caught by the index.html catch-all.\n configureServer(server) {\n // Idempotency guard: the CLI injects this plugin and a vite.config may\n // also wire it — only register the middleware once.\n const flagged = server as unknown as { __fluidBackendDevWired?: boolean };\n if (flagged.__fluidBackendDevWired) return;\n flagged.__fluidBackendDevWired = true;\n\n server.middlewares.use((req, res, next) => {\n const raw = req.url ?? \"\";\n const qIndex = raw.indexOf(\"?\");\n const url = qIndex === -1 ? raw : raw.slice(0, qIndex);\n\n if (url === \"/portal.js\") {\n serve(\n res,\n \"application/javascript\",\n [\n `import RefreshRuntime from \"/@react-refresh\";`,\n `import \"/@vite/client\";`,\n `RefreshRuntime.injectIntoGlobalHook(window);`,\n `window.$RefreshReg$ = () => {};`,\n `window.$RefreshSig$ = () => (type) => type;`,\n `window.__vite_plugin_react_preamble_installed__ = true;`,\n `await import(\"${entry}\");`,\n ].join(\"\\n\"),\n );\n return;\n }\n\n if (url === \"/portal.css\") {\n serve(res, \"text/css\", \"/* dev: CSS injected via JS */\");\n return;\n }\n\n const chunkName = url.startsWith(\"/\") ? url.slice(1) : url;\n if (chunks.includes(chunkName)) {\n serve(res, \"application/javascript\", \"export {};\");\n return;\n }\n\n next();\n });\n },\n };\n}\n\nfunction serve(\n res: import(\"http\").ServerResponse,\n contentType: string,\n body: string,\n) {\n res.setHeader(\"Content-Type\", `${contentType}; charset=utf-8`);\n res.setHeader(\"Cache-Control\", \"no-store\");\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n res.statusCode = 200;\n res.end(body);\n}\n"],"mappings":";;;;;;;;;;;;;AAmBA,SAAgB,iBAAiB,SAA2C;CAC1E,MAAM,QAAQ,SAAS,SAAS;CAChC,MAAM,SAAS,SAAS,UAAU,CAAC,aAAa,WAAW;AAE3D,QAAO;EACL,MAAM;EACN,OAAO;EAIP,gBAAgB,QAAQ;GAGtB,MAAM,UAAU;AAChB,OAAI,QAAQ,uBAAwB;AACpC,WAAQ,yBAAyB;AAEjC,UAAO,YAAY,KAAK,KAAK,KAAK,SAAS;IACzC,MAAM,MAAM,IAAI,OAAO;IACvB,MAAM,SAAS,IAAI,QAAQ,IAAI;IAC/B,MAAM,MAAM,WAAW,KAAK,MAAM,IAAI,MAAM,GAAG,OAAO;AAEtD,QAAI,QAAQ,cAAc;AACxB,WACE,KACA,0BACA;MACE;MACA;MACA;MACA;MACA;MACA;MACA,iBAAiB,MAAM;MACxB,CAAC,KAAK,KAAK,CACb;AACD;;AAGF,QAAI,QAAQ,eAAe;AACzB,WAAM,KAAK,YAAY,iCAAiC;AACxD;;IAGF,MAAM,YAAY,IAAI,WAAW,IAAI,GAAG,IAAI,MAAM,EAAE,GAAG;AACvD,QAAI,OAAO,SAAS,UAAU,EAAE;AAC9B,WAAM,KAAK,0BAA0B,aAAa;AAClD;;AAGF,UAAM;KACN;;EAEL;;AAGH,SAAS,MACP,KACA,aACA,MACA;AACA,KAAI,UAAU,gBAAgB,GAAG,YAAY,iBAAiB;AAC9D,KAAI,UAAU,iBAAiB,WAAW;AAC1C,KAAI,UAAU,+BAA+B,IAAI;AACjD,KAAI,aAAa;AACjB,KAAI,IAAI,KAAK"}
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as toFluidOsDynamicObject, C as resolveIdToSlug, D as atomicWriteFile, E as writeMappings, M as ApiError, O as createFluidOsClient, S as removeMapping, T as updateMapping, _ as diffAgainstSnapshot, a as buildNavigationIdToSlugMap, b as deriveSlug, c as transformNavigation, d as transformScreen, f as transformTheme, g as computeFileHash, h as collectSnapshotNetworkWidgetGrants, i as buildIdToSlugMap, j as createFluidOsHeyApiClient, k as fluidOsApi, l as transformNavigationItems, m as collectNetworkWidgetGrants, o as buildThemeIdToSlugMap, p as buildSnapshot, r as validatePortalResource, s as deriveScreenSlug, t as pullCommand, u as transformProfile, v as readSnapshot, w as resolveSlugToId, x as readMappings, y as writeSnapshot } from "./pull-BWnby_pY.mjs";
1
+ import { A as toFluidOsDynamicObject, C as resolveIdToSlug, D as atomicWriteFile, E as writeMappings, M as ApiError, O as createFluidOsClient, S as removeMapping, T as updateMapping, _ as diffAgainstSnapshot, a as buildNavigationIdToSlugMap, b as deriveSlug, c as transformNavigation, d as transformScreen, f as transformTheme, g as computeFileHash, h as collectSnapshotNetworkWidgetGrants, i as buildIdToSlugMap, j as createFluidOsHeyApiClient, k as fluidOsApi, l as transformNavigationItems, m as collectNetworkWidgetGrants, o as buildThemeIdToSlugMap, p as buildSnapshot, r as validatePortalResource, s as deriveScreenSlug, t as pullCommand, u as transformProfile, v as readSnapshot, w as resolveSlugToId, x as readMappings, y as writeSnapshot } from "./pull-Kx1ncTLF.mjs";
2
2
  import { l as fluidOsV0DefinitionGitCredentialCreate } from "./sdk.gen-VRGYiLVJ.mjs";
3
3
  import { a as resolvePublishVersion, d as isRemoteDomWidgetPackageDescriptor, i as readCompanyWidgetPackages, n as preflightCompanyPackage, o as loadAndValidateWidgetPackage, r as readCompanyWidgetPackage, s as publishWidgetPackage, t as formatPackageKeyMismatch } from "./src-D1cU2gmw.mjs";
4
4
  import { Command } from "commander";
@@ -96,9 +96,9 @@ async function promptProjectConfig(projectName, options) {
96
96
  //#endregion
97
97
  //#region src/utils/file-system.ts
98
98
  const _currentDir$1 = dirname(fileURLToPath(import.meta.url));
99
- const EMBEDDED_PORTAL_SDK_VERSION = "0.1.486";
99
+ const EMBEDDED_PORTAL_SDK_VERSION = "0.1.485";
100
100
  const EMBEDDED_CLI_CORE_VERSION = "0.1.19";
101
- const EMBEDDED_CLI_PORTAL_VERSION = "0.1.78";
101
+ const EMBEDDED_CLI_PORTAL_VERSION = "0.1.79";
102
102
  /**
103
103
  * Find the package root by walking up from the current directory to the nearest package.json.
104
104
  * Works whether running from dist/ (bundled) or src/utils/ (tsx dev mode).
@@ -1640,7 +1640,7 @@ async function autoPull(cwd) {
1640
1640
  console.log(chalk.yellow("No portal/ directory found.") + " Attempting to pull content...");
1641
1641
  console.log();
1642
1642
  try {
1643
- const { pullCommand } = await import("./pull-BWnby_pY.mjs").then((n) => n.n);
1643
+ const { pullCommand } = await import("./pull-Kx1ncTLF.mjs").then((n) => n.n);
1644
1644
  await pullCommand.parseAsync([], { from: "user" });
1645
1645
  return hasPortalContent(cwd);
1646
1646
  } catch (err) {
@@ -1693,9 +1693,9 @@ const devCommand = new Command("dev").description("Start the development server
1693
1693
  const port = Number.isFinite(parsedPort) ? parsedPort : 5173;
1694
1694
  try {
1695
1695
  const { createServer } = await import("vite");
1696
- const { portalDevPlugin } = await import("./portal-dev-plugin-2jZODDsX.mjs").then((n) => n.n);
1697
- const { backendDevPlugin } = await import("./backend-dev-plugin-z9IZCHaY.mjs").then((n) => n.n);
1698
- const { portalWidgetDevPlugin } = await import("./portal-widget-dev-plugin-CO-im-5P.mjs").then((n) => n.n);
1696
+ const { portalDevPlugin } = await import("./portal-dev-plugin-BFqDxRMa.mjs").then((n) => n.n);
1697
+ const { backendDevPlugin } = await import("./backend-dev-plugin-Dy2Fcdg7.mjs").then((n) => n.n);
1698
+ const { portalWidgetDevPlugin } = await import("./portal-widget-dev-plugin-Dis7d954.mjs").then((n) => n.n);
1699
1699
  const server = await createServer({
1700
1700
  configFile: viteConfigPath,
1701
1701
  envPrefix: ["VITE_", "NEXT_PUBLIC_"],
@@ -1991,27 +1991,63 @@ async function validateCrossReferences(portalDir, mappings, changes) {
1991
1991
  }
1992
1992
  const profileFilesToCheck = [...changes.profiles.new, ...changes.profiles.changed];
1993
1993
  for (const file of profileFilesToCheck) try {
1994
- const profile = await readPortalFile$1(portalDir, file);
1995
- if (profile.navigation && !validNavSlugs.has(profile.navigation)) errors.push({
1996
- file,
1997
- message: `References navigation "${profile.navigation}" which does not exist`
1998
- });
1999
- if (profile.mobile_navigation && !validNavSlugs.has(profile.mobile_navigation)) errors.push({
2000
- file,
2001
- message: `References mobile_navigation "${profile.mobile_navigation}" which does not exist`
2002
- });
2003
- for (const themeSlug of profile.themes ?? []) if (!validThemeSlugs.has(themeSlug)) errors.push({
2004
- file,
2005
- message: `References theme "${themeSlug}" which does not exist`
2006
- });
1994
+ validateProfileReferences(await readPortalFile$1(portalDir, file), file, validNavSlugs, validThemeSlugs, errors);
2007
1995
  } catch {
2008
1996
  errors.push({
2009
1997
  file,
2010
1998
  message: "Failed to read profile file"
2011
1999
  });
2012
2000
  }
2001
+ if (changes.screens.deleted.length > 0) {
2002
+ const alreadyChecked = new Set(navFilesToCheck);
2003
+ for (const file of listResourceFiles(portalDir, "navigations")) {
2004
+ if (alreadyChecked.has(file)) continue;
2005
+ const nav = await readPortalFileOrNull(portalDir, file);
2006
+ if (!nav || !Array.isArray(nav.navigation_items)) continue;
2007
+ validateNavigationItems(nav.navigation_items, file, validScreenSlugs, errors);
2008
+ }
2009
+ }
2010
+ if (changes.navigations.deleted.length > 0 || changes.themes.deleted.length > 0) {
2011
+ const alreadyChecked = new Set(profileFilesToCheck);
2012
+ for (const file of listResourceFiles(portalDir, "profiles")) {
2013
+ if (alreadyChecked.has(file)) continue;
2014
+ const profile = await readPortalFileOrNull(portalDir, file);
2015
+ if (!profile) continue;
2016
+ validateProfileReferences(profile, file, validNavSlugs, validThemeSlugs, errors);
2017
+ }
2018
+ }
2013
2019
  return errors;
2014
2020
  }
2021
+ function listResourceFiles(portalDir, resourceType) {
2022
+ const directory = join(portalDir, resourceType);
2023
+ if (!existsSync(directory)) return [];
2024
+ try {
2025
+ return collectJsonFiles(directory).map((file) => `${resourceType}/${file}`);
2026
+ } catch {
2027
+ return [];
2028
+ }
2029
+ }
2030
+ async function readPortalFileOrNull(portalDir, relativePath) {
2031
+ try {
2032
+ return await readPortalFile$1(portalDir, relativePath);
2033
+ } catch {
2034
+ return null;
2035
+ }
2036
+ }
2037
+ function validateProfileReferences(profile, file, validNavSlugs, validThemeSlugs, errors) {
2038
+ if (profile.navigation && !validNavSlugs.has(profile.navigation)) errors.push({
2039
+ file,
2040
+ message: `References navigation "${profile.navigation}" which does not exist`
2041
+ });
2042
+ if (profile.mobile_navigation && !validNavSlugs.has(profile.mobile_navigation)) errors.push({
2043
+ file,
2044
+ message: `References mobile_navigation "${profile.mobile_navigation}" which does not exist`
2045
+ });
2046
+ for (const themeSlug of profile.themes ?? []) if (!validThemeSlugs.has(themeSlug)) errors.push({
2047
+ file,
2048
+ message: `References theme "${themeSlug}" which does not exist`
2049
+ });
2050
+ }
2015
2051
  /**
2016
2052
  * Warns about screens the admin visual builder will not accept drops on.
2017
2053
  *