@fluid-app/fluid-cli-portal 0.1.82 → 0.1.84

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 +1 @@
1
- {"version":3,"file":"vite-plugin.d.mts","names":[],"sources":["../src/vite-plugin/portal-dev-plugin.ts","../src/vite-plugin/backend-dev-plugin.ts","../src/vite-plugin/portal-widget-dev-plugin.ts"],"mappings":";;;;;UAmBiB,sBAAA;EACf,SAAA;;AADF;;;;;;;;EAWE,aAAA;;;AA4KF;;;EAtKE,cAAA;EAsKwC;;;;EAjKxC,sBAAA,SAA+B,OAAA;AAAA;AAAA,iBAiKjB,eAAA,CAAgB,OAAA,GAAU,sBAAA;;;UCxMzB,uBAAA;;EAEf,KAAA;EDeF;ECbE,MAAA;AAAA;;;;;;;;;ADoMF;;iBCvLgB,gBAAA,CAAiB,OAAA,GAAU,uBAAA,GAA0B,MAAA;;;iBC6CrD,qBAAA,CAAA,GAAyB,MAAA"}
1
+ {"version":3,"file":"vite-plugin.d.mts","names":[],"sources":["../src/vite-plugin/portal-dev-plugin.ts","../src/vite-plugin/backend-dev-plugin.ts","../src/vite-plugin/portal-widget-dev-plugin.ts"],"mappings":";;;;;UAmBiB,sBAAA;EACf,SAAA;;AADF;;;;;;;;EAWE,aAAA;;;AA4KF;;;EAtKE,cAAA;EAsKwC;;;;EAjKxC,sBAAA,SAA+B,OAAA;AAAA;AAAA,iBAiKjB,eAAA,CAAgB,OAAA,GAAU,sBAAA;;;UCxMzB,uBAAA;;EAEf,KAAA;EDeF;ECbE,MAAA;AAAA;;;;;;;;;ADoMF;;iBCvLgB,gBAAA,CAAiB,OAAA,GAAU,uBAAA,GAA0B,MAAA;;;iBCgDrD,qBAAA,CAAA,GAAyB,MAAA"}
@@ -1,6 +1,6 @@
1
1
  import "./src-BuSYN4Co.mjs";
2
2
  import { buildManifestFromLocalFiles, listLocalProfiles } from "./build-manifest.mjs";
3
- import { t as portalDevPlugin } from "./portal-dev-plugin-C6TJcQmL.mjs";
4
- import { t as backendDevPlugin } from "./backend-dev-plugin-C3gcb6LF.mjs";
5
- import { t as portalWidgetDevPlugin } from "./portal-widget-dev-plugin-BFyun5DF.mjs";
3
+ import { t as portalDevPlugin } from "./portal-dev-plugin-CzQGHgMv.mjs";
4
+ import { t as backendDevPlugin } from "./backend-dev-plugin-CCIGu1Ly.mjs";
5
+ import { t as portalWidgetDevPlugin } from "./portal-widget-dev-plugin-CpThuSXZ.mjs";
6
6
  export { backendDevPlugin, buildManifestFromLocalFiles, listLocalProfiles, portalDevPlugin, portalWidgetDevPlugin };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluid-app/fluid-cli-portal",
3
- "version": "0.1.82",
3
+ "version": "0.1.84",
4
4
  "description": "Fluid CLI plugin for building portal applications",
5
5
  "files": [
6
6
  "authoring",
@@ -50,15 +50,15 @@
50
50
  "jest": "^29.7.0",
51
51
  "tsdown": "^0.21.0",
52
52
  "typescript": "^5",
53
- "@fluid-app/fluidos-api-client": "0.1.0",
54
- "@fluid-app/fluid-cli-widget-tooling": "0.1.0",
55
53
  "@fluid-app/api-client-core": "0.1.0",
56
54
  "@fluid-app/portal-core": "0.1.23",
57
- "@fluid-app/portal-definition-schema": "1.4.0",
58
- "@fluid-app/portal-sdk": "0.1.488",
55
+ "@fluid-app/fluid-cli-widget-tooling": "0.1.0",
56
+ "@fluid-app/fluidos-api-client": "0.1.0",
57
+ "@fluid-app/portal-sdk": "0.1.490",
58
+ "@fluid-app/portal-definition-schema": "1.5.0",
59
59
  "@fluid-app/portal-widgets": "0.1.22",
60
- "@fluid-app/typescript-config": "0.0.0",
61
- "@fluid-app/theme-engine": "0.1.0"
60
+ "@fluid-app/theme-engine": "0.1.0",
61
+ "@fluid-app/typescript-config": "0.0.0"
62
62
  },
63
63
  "engines": {
64
64
  "node": ">=24.0.0"
@@ -1,5 +1,9 @@
1
1
  import { createPortal } from "@fluid-app/portal-sdk";
2
+ import fluidComponentCssUrl from "@fluid-app/portal-sdk/remote-widget-shadow.css?url";
2
3
  import { customPages } from "./portal.config";
3
4
  import "./index.css";
4
5
 
5
- createPortal({ customPages });
6
+ createPortal({
7
+ customPages,
8
+ remoteWidgets: { fluidComponentCssUrls: [fluidComponentCssUrl] },
9
+ });
@@ -16,9 +16,11 @@ export default defineConfig({
16
16
  output: {
17
17
  entryFileNames: "portal.js",
18
18
  assetFileNames: (asset) =>
19
- asset.names?.some((n) => n.endsWith(".css"))
20
- ? "portal.[ext]"
21
- : "assets/[name].[ext]",
19
+ asset.names?.some((name) => name.endsWith("remote-widget-shadow.css"))
20
+ ? "remote-widget-shadow.[ext]"
21
+ : asset.names?.some((name) => name.endsWith(".css"))
22
+ ? "portal.[ext]"
23
+ : "assets/[name].[ext]",
22
24
  chunkFileNames: (chunk) =>
23
25
  `${chunk.name.replace(/-[A-Za-z0-9_-]{8}$/, "")}.js`,
24
26
  manualChunks(id) {
@@ -1 +0,0 @@
1
- {"version":3,"file":"backend-dev-plugin-C3gcb6LF.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 +0,0 @@
1
- {"version":3,"file":"portal-widget-dev-plugin-BFyun5DF.mjs","names":[],"sources":["../src/vite-plugin/portal-widget-dev-plugin.ts"],"sourcesContent":["/**\n * Dev routes that let a portal preview render the project's own widgets before\n * they are published.\n *\n * A portal keeps company-owned widget sources in `src/widgets.config.ts` and\n * publishes them with `fluid portal deploy`. Until that deploy runs, the widget\n * exists only on disk — the catalog has never heard of it, so a preview could\n * not show it and the only way to see your work was to publish it. Publishing\n * is not a safe iteration loop: a deploy is live immediately, there is no\n * rollback, and a duplicate `packageId@version` is ignored so every attempt\n * needs a version bump.\n *\n * These routes close that gap by serving the same two endpoints a standalone\n * widget project serves — `/__widget-packages__` (a canonical package\n * descriptor) and `/__runtime-entry__` (the worker bootstrap). A host that can\n * already render published packages needs no new code to render a local one:\n * the descriptor shape is identical, so it merges straight into the catalog\n * array.\n *\n * The route implementations are reused wholesale from\n * `@fluid-app/fluid-cli-widget-tooling`. Its bootstrap script in particular is\n * load-bearing — it exists to fix a message-buffer race that silently strands\n * worker mounts — and must not be reimplemented here.\n *\n * Imported from widget-tooling rather than from the widget CLI deliberately:\n * this package lists widget-tooling in its tsdown `alwaysBundle`, so the routes\n * compile into the portal dist. An import across published CLIs stays external\n * and resolves to un-built TypeScript at runtime.\n *\n * Two things differ from a standalone project, and both are passed as options:\n * the package source lives at `src/widgets.config.ts` rather than\n * `fluid.widget.config.ts`, and it is owned by `company` rather than `droplet`.\n * A portal also has no `startWidgetPackage()` module of its own, so this plugin\n * generates one.\n */\n\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport {\n fluidWidgetDevPlugin,\n handleOptions,\n setCorsHeaders,\n} from \"@fluid-app/fluid-cli-widget-tooling\";\nimport type { Plugin } from \"vite\";\n\n/** Package source, relative to the Vite root. */\nconst WIDGET_CONFIG_MODULE_PATH = \"/src/widgets.config.ts\";\n\n/**\n * Generated worker entry. Requestable (no `\\0` prefix) because the bootstrap\n * script imports it by URL from the dev server rather than through Vite's\n * module graph.\n */\nconst VIRTUAL_ENTRY_PATH = \"/@fluid-portal-widget-entry.js\";\n\nconst WIDGET_PACKAGES_ROUTES = new Set([\n \"/__widget-packages__\",\n \"/__widget-packages__/\",\n]);\nconst RUNTIME_ENTRY_ROUTES = new Set([\n \"/__runtime-entry__\",\n \"/__runtime-entry__/\",\n]);\n\nexport function portalWidgetDevPlugin(): Plugin[] {\n return [\n missingConfigGuardPlugin(),\n virtualWorkerEntryPlugin(),\n fluidWidgetDevPlugin({\n entryModulePath: VIRTUAL_ENTRY_PATH,\n configModulePath: WIDGET_CONFIG_MODULE_PATH,\n owner: \"company\",\n // A portal with no custom widget yet is the normal case, not a fault.\n allowNoPackages: true,\n }),\n ];\n}\n\n/**\n * Short-circuits both routes when the project has no `src/widgets.config.ts`.\n *\n * Most portals never gain one. Without this the delegated routes would try to\n * load a module that does not exist and log a resolution failure on every poll\n * — the preview polls continuously — so the expected case would be the noisiest\n * thing in the log. Registered before the delegated plugin so its middleware\n * runs first.\n */\nfunction missingConfigGuardPlugin(): Plugin {\n let configFilePath = \"\";\n\n return {\n name: \"fluid-portal-widget-dev-missing-config-guard\",\n apply: \"serve\",\n configResolved(config) {\n configFilePath = path.join(\n config.root,\n WIDGET_CONFIG_MODULE_PATH.replace(/^\\//, \"\"),\n );\n },\n configureServer(server) {\n server.middlewares.use((request, response, next): void => {\n const pathname = (request.url ?? \"\").split(\"?\")[0] ?? \"\";\n const isWidgetRoute =\n WIDGET_PACKAGES_ROUTES.has(pathname) ||\n RUNTIME_ENTRY_ROUTES.has(pathname);\n if (!isWidgetRoute) {\n next();\n return;\n }\n // Checked per request, not at startup: `fluid portal widget create`\n // can add the file while the dev server is already running.\n if (existsSync(configFilePath)) {\n next();\n return;\n }\n\n // Answer a preflight exactly as the delegated routes do. Two\n // implementations of the same route disagreeing is bad enough; the\n // guard is the one that runs in the common case, since most portals\n // never gain a widget config, so the divergence would have been the\n // DEFAULT path rather than the edge.\n if (handleOptions(request, response)) return;\n setCorsHeaders(response);\n if (WIDGET_PACKAGES_ROUTES.has(pathname)) {\n response.setHeader(\"Content-Type\", \"application/json\");\n response.statusCode = 200;\n response.end(\"[]\");\n return;\n }\n response.setHeader(\"Content-Type\", \"text/javascript\");\n response.statusCode = 200;\n response.end(\"// No portal widget package in this project.\\n\");\n });\n },\n };\n}\n\n/**\n * Serves the worker entry a portal project does not have.\n *\n * A standalone widget project ships `src/index.ts` calling\n * `startWidgetPackage()`. A portal's `src/widgets.config.ts` only declares the\n * package, so this module supplies the missing call. Export precedence matches\n * the shared descriptor builder's, so the worker starts the same package the\n * descriptor advertises.\n */\nfunction virtualWorkerEntryPlugin(): Plugin {\n return {\n name: \"fluid-portal-widget-dev-entry\",\n apply: \"serve\",\n resolveId(id) {\n return id === VIRTUAL_ENTRY_PATH ? id : null;\n },\n load(id) {\n if (id !== VIRTUAL_ENTRY_PATH) return null;\n return `import { prepareRemoteDomWidgetWorker, startWidgetPackage } from \"@fluid-app/portal-sdk/widgets/worker\";\n\nprepareRemoteDomWidgetWorker();\nconst source = await import(\"${WIDGET_CONFIG_MODULE_PATH}\");\n\nconst packages = source.widgetPackages;\nconst widgetPackage =\n (Array.isArray(packages) && packages.length > 0 ? packages[0] : undefined) ??\n source.widgetPackage ??\n source.default;\n\nif (widgetPackage) {\n startWidgetPackage(widgetPackage);\n}\n`;\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CA,MAAM,4BAA4B;;;;;;AAOlC,MAAM,qBAAqB;AAE3B,MAAM,yBAAyB,IAAI,IAAI,CACrC,wBACA,wBACD,CAAC;AACF,MAAM,uBAAuB,IAAI,IAAI,CACnC,sBACA,sBACD,CAAC;AAEF,SAAgB,wBAAkC;AAChD,QAAO;EACL,0BAA0B;EAC1B,0BAA0B;EAC1B,qBAAqB;GACnB,iBAAiB;GACjB,kBAAkB;GAClB,OAAO;GAEP,iBAAiB;GAClB,CAAC;EACH;;;;;;;;;;;AAYH,SAAS,2BAAmC;CAC1C,IAAI,iBAAiB;AAErB,QAAO;EACL,MAAM;EACN,OAAO;EACP,eAAe,QAAQ;AACrB,oBAAiB,KAAK,KACpB,OAAO,MACP,0BAA0B,QAAQ,OAAO,GAAG,CAC7C;;EAEH,gBAAgB,QAAQ;AACtB,UAAO,YAAY,KAAK,SAAS,UAAU,SAAe;IACxD,MAAM,YAAY,QAAQ,OAAO,IAAI,MAAM,IAAI,CAAC,MAAM;AAItD,QAAI,EAFF,uBAAuB,IAAI,SAAS,IACpC,qBAAqB,IAAI,SAAS,GAChB;AAClB,WAAM;AACN;;AAIF,QAAI,WAAW,eAAe,EAAE;AAC9B,WAAM;AACN;;AAQF,QAAI,cAAc,SAAS,SAAS,CAAE;AACtC,mBAAe,SAAS;AACxB,QAAI,uBAAuB,IAAI,SAAS,EAAE;AACxC,cAAS,UAAU,gBAAgB,mBAAmB;AACtD,cAAS,aAAa;AACtB,cAAS,IAAI,KAAK;AAClB;;AAEF,aAAS,UAAU,gBAAgB,kBAAkB;AACrD,aAAS,aAAa;AACtB,aAAS,IAAI,iDAAiD;KAC9D;;EAEL;;;;;;;;;;;AAYH,SAAS,2BAAmC;AAC1C,QAAO;EACL,MAAM;EACN,OAAO;EACP,UAAU,IAAI;AACZ,UAAO,OAAO,qBAAqB,KAAK;;EAE1C,KAAK,IAAI;AACP,OAAI,OAAO,mBAAoB,QAAO;AACtC,UAAO;;;+BAGkB,0BAA0B;;;;;;;;;;;;;EAatD"}