@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.
- package/dist/{backend-dev-plugin-z9IZCHaY.mjs → backend-dev-plugin-Dy2Fcdg7.mjs} +2 -2
- package/dist/{backend-dev-plugin-z9IZCHaY.mjs.map → backend-dev-plugin-Dy2Fcdg7.mjs.map} +1 -1
- package/dist/index.mjs +56 -20
- package/dist/index.mjs.map +1 -1
- package/dist/{portal-dev-plugin-2jZODDsX.mjs → portal-dev-plugin-BFqDxRMa.mjs} +23 -24
- package/dist/{portal-dev-plugin-2jZODDsX.mjs.map → portal-dev-plugin-BFqDxRMa.mjs.map} +1 -1
- package/dist/{portal-widget-dev-plugin-CO-im-5P.mjs → portal-widget-dev-plugin-Dis7d954.mjs} +2 -2
- package/dist/{portal-widget-dev-plugin-CO-im-5P.mjs.map → portal-widget-dev-plugin-Dis7d954.mjs.map} +1 -1
- package/dist/{pull-BWnby_pY.mjs → pull-Kx1ncTLF.mjs} +73 -19
- package/dist/{pull-BWnby_pY.mjs.map → pull-Kx1ncTLF.mjs.map} +1 -1
- package/dist/vite-plugin.mjs +3 -3
- package/package.json +6 -6
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { N as __exportAll } from "./pull-
|
|
1
|
+
import { N as __exportAll } from "./pull-Kx1ncTLF.mjs";
|
|
2
2
|
import { buildManifestFromLocalFiles } from "./build-manifest.mjs";
|
|
3
3
|
import { join, resolve, sep } from "node:path";
|
|
4
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -158,28 +158,27 @@ function portalDevPlugin(options) {
|
|
|
158
158
|
if (server.__fluidPortalDevWired) return;
|
|
159
159
|
server.__fluidPortalDevWired = true;
|
|
160
160
|
const watchDir = portalDir;
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
161
|
+
server.watcher.add(watchDir);
|
|
162
|
+
let reloadTimer = null;
|
|
163
|
+
const watchDirPrefix = watchDir.endsWith(sep) ? watchDir : watchDir + sep;
|
|
164
|
+
const onFileChange = (filePath) => {
|
|
165
|
+
if (filePath !== watchDir && !filePath.startsWith(watchDirPrefix)) return;
|
|
166
|
+
cachedManifest = null;
|
|
167
|
+
buildInFlight = null;
|
|
168
|
+
manifestGeneration += 1;
|
|
169
|
+
console.log(`[fluid-portal-dev] File changed: ${filePath.replace(watchDirPrefix, "")}`);
|
|
170
|
+
if (reloadTimer) clearTimeout(reloadTimer);
|
|
171
|
+
reloadTimer = setTimeout(() => {
|
|
172
|
+
reloadTimer = null;
|
|
173
|
+
server.ws.send({
|
|
174
|
+
type: "full-reload",
|
|
175
|
+
path: "*"
|
|
176
|
+
});
|
|
177
|
+
}, DEBOUNCE_MS);
|
|
178
|
+
};
|
|
179
|
+
server.watcher.on("change", onFileChange);
|
|
180
|
+
server.watcher.on("add", onFileChange);
|
|
181
|
+
server.watcher.on("unlink", onFileChange);
|
|
183
182
|
server.middlewares.use((req, res, next) => {
|
|
184
183
|
const url = req.url;
|
|
185
184
|
if (!url || !MANIFEST_PATHS.some((path) => url.includes(path))) {
|
|
@@ -229,4 +228,4 @@ function portalDevPlugin(options) {
|
|
|
229
228
|
//#endregion
|
|
230
229
|
export { portal_dev_plugin_exports as n, portalDevPlugin as t };
|
|
231
230
|
|
|
232
|
-
//# sourceMappingURL=portal-dev-plugin-
|
|
231
|
+
//# sourceMappingURL=portal-dev-plugin-BFqDxRMa.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"portal-dev-plugin-2jZODDsX.mjs","names":[],"sources":["../src/vite-plugin/portal-dev-plugin.ts"],"sourcesContent":["/**\n * Vite plugin for local portal content development.\n *\n * Intercepts the manifest API request and serves content assembled from the\n * local `portal/` directory. Watches portal files for changes and triggers a\n * full page reload.\n *\n * The manifest is intercepted on BOTH paths the SDK has used across versions\n * (`/api/app/manifest` since portal-sdk 0.1.4xx, `/api/fluid_os/definitions/\n * active` before that) so a newer SDK against an older-generation app — or\n * vice versa — still gets the local draft.\n */\n\nimport { join, resolve, sep } from \"node:path\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { getAuthToken, getFluidApiBase } from \"@fluid-app/fluid-cli\";\nimport { buildManifestFromLocalFiles } from \"./build-manifest.js\";\n\n/** Options for the portal dev plugin. */\nexport interface PortalDevPluginOptions {\n portalDir?: string;\n /**\n * When true (default), dev-server requests are forced same-origin: the\n * plugin blanks `import.meta.env.VITE_API_URL` in serve mode and proxies\n * `/api` to the configured Fluid host instead. Without this, a `.env`\n * pointing VITE_API_URL at a remote API makes the SPA fetch its manifest\n * cross-origin — silently bypassing this plugin and rendering the remote\n * app instead of the local `portal/` draft. Set false to opt out and let\n * the SPA call the remote API directly.\n */\n sameOriginDev?: boolean;\n /**\n * Override the `/api` dev-proxy target. Defaults to VITE_API_URL from the\n * process env / .env files, then the authenticated company's\n * `<subdomain>.portal.fluid.app` tenant BFF, then https://api.fluid.app.\n */\n apiProxyTarget?: string;\n /**\n * Override tenant-target discovery. Primarily useful to keep embedded plugin\n * integrations and tests deterministic.\n */\n resolveTenantApiTarget?: () => Promise<string | undefined>;\n}\n\nconst DEBOUNCE_MS = 100;\n\n/** Manifest endpoints across SDK generations — all serve the local draft. */\nconst MANIFEST_PATHS = [\n \"/api/app/manifest\",\n \"/api/fluid_os/definitions/active\",\n];\n\nconst DEFAULT_API_URL = \"https://api.fluid.app\";\nconst TENANT_LOOKUP_TIMEOUT_MS = 3_000;\nconst tenantTargetPromises = new WeakMap<\n () => Promise<string | undefined>,\n Promise<string | undefined>\n>();\n\ninterface CompanyMeResponse {\n data?: {\n company?: {\n subdomain?: unknown;\n };\n };\n}\n\nexport interface TenantApiTargetDependencies {\n token?: string | null;\n apiBase?: string;\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n}\n\n/**\n * Resolve the portal tenant BFF for the CLI's project-aware Fluid profile.\n *\n * Portal member APIs do not live on api.fluid.app or `<tenant>.fluid.app`.\n * Their OpenAPI server is `<tenant>.portal.fluid.app`, and using either of\n * the former hosts produces a wall of unrelated 404s in otherwise-valid\n * local portals.\n */\nexport async function resolvePortalTenantApiTarget(\n dependencies: TenantApiTargetDependencies = {},\n): Promise<string | undefined> {\n const token =\n dependencies.token !== undefined ? dependencies.token : getAuthToken();\n if (!token) return undefined;\n\n const controller = new AbortController();\n const timer = setTimeout(\n () => controller.abort(),\n dependencies.timeoutMs ?? TENANT_LOOKUP_TIMEOUT_MS,\n );\n\n try {\n const response = await (dependencies.fetchImpl ?? fetch)(\n `${(dependencies.apiBase ?? getFluidApiBase()).replace(/\\/+$/, \"\")}/api/company/v1/companies/me`,\n {\n headers: {\n Authorization: `Bearer ${token}`,\n Accept: \"application/json\",\n },\n signal: controller.signal,\n },\n );\n if (!response.ok) return undefined;\n\n const body = (await response.json()) as CompanyMeResponse;\n const subdomain = body.data?.company?.subdomain;\n if (\n typeof subdomain !== \"string\" ||\n !/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(subdomain)\n ) {\n return undefined;\n }\n\n return `https://${subdomain}.portal.fluid.app`;\n } catch {\n return undefined;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Fallback .env reader for VITE_API_URL, used only when vite's `loadEnv`\n * can't be imported (it's a declared dependency, so this is defensive — but\n * a broken install must degrade to \"wrong host\" rather than \"dev server\n * won't boot\"). Mirrors the basic lookup order: live env > .env.local >\n * .env. Unlike loadEnv it ignores .env.[mode] files and variable expansion.\n */\nfunction readViteApiUrlFallback(root: string): string | undefined {\n if (process.env.VITE_API_URL) return process.env.VITE_API_URL;\n if (process.env.NEXT_PUBLIC_API_BASE_URL) {\n return process.env.NEXT_PUBLIC_API_BASE_URL;\n }\n for (const file of [\".env.local\", \".env\"]) {\n const path = join(root, file);\n if (!existsSync(path)) continue;\n for (const line of readFileSync(path, \"utf8\").split(\"\\n\")) {\n // Quoted values stop at the closing `\"`; unquoted values stop before\n // an inline ` # comment` tail (dotenv semantics — a trailing comment\n // must not leak into the proxy target URL).\n const match =\n /^\\s*VITE_API_URL\\s*=\\s*(?:\"([^\"]*)\"|(.*?))\\s*(?:#.*)?$/.exec(line);\n const value = match?.[1] ?? match?.[2];\n if (value) return value;\n }\n }\n return undefined;\n}\n\nfunction storefrontSubdomainFromTarget(target: string): string | undefined {\n try {\n const hostname = new URL(target).hostname;\n const match = /^([a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\\.fluid\\.app$/.exec(\n hostname,\n );\n const subdomain = match?.[1];\n if (\n !subdomain ||\n [\"admin\", \"api\", \"app\", \"docs\", \"portal\", \"upload\"].includes(subdomain)\n ) {\n return undefined;\n }\n return subdomain;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolve VITE_API_URL the way vite itself would — `loadEnv` honors\n * .env.[mode], .env.[mode].local, envDir, and variable expansion, which the\n * fallback parser does not (a mode-specific staging API must not silently\n * fall back to production).\n */\nasync function resolveViteApiUrl(\n root: string,\n mode: string,\n envDir: string | undefined,\n): Promise<string | undefined> {\n try {\n const { loadEnv } = await import(\"vite\");\n const env = loadEnv(mode, envDir ?? root, [\"VITE_\", \"NEXT_PUBLIC_\"]);\n return (\n env.VITE_API_URL ||\n process.env.VITE_API_URL ||\n // Portals migrated from Next.js conventions configure the API host as\n // NEXT_PUBLIC_API_BASE_URL — honored by `fluid portal dev` since it\n // was introduced, so it stays a recognized source here.\n env.NEXT_PUBLIC_API_BASE_URL ||\n process.env.NEXT_PUBLIC_API_BASE_URL ||\n undefined\n );\n } catch {\n return readViteApiUrlFallback(root);\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function portalDevPlugin(options?: PortalDevPluginOptions): any {\n let portalDir: string;\n let cachedManifest: string | null = null;\n let buildInFlight: Promise<string> | null = null;\n /** Bumped on every watched file change. A build carries the value it\n * started under; if it no longer matches when the build resolves, the\n * build read pre-edit state and must not be cached. */\n let manifestGeneration = 0;\n const resolveTenantTarget =\n options?.resolveTenantApiTarget ?? resolvePortalTenantApiTarget;\n\n return {\n name: \"fluid-portal-dev\",\n enforce: \"pre\" as const,\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async config(config: any, env: any) {\n if (env?.command !== \"serve\" || options?.sameOriginDev === false) {\n return {};\n }\n\n const root: string = config.root ?? process.cwd();\n const appDefinesProxy = config.server?.proxy?.[\"/api\"] !== undefined;\n const configuredTarget =\n options?.apiProxyTarget || appDefinesProxy\n ? undefined\n : await resolveViteApiUrl(\n root,\n env?.mode ?? \"development\",\n config.envDir,\n );\n const tenantTarget =\n options?.apiProxyTarget || appDefinesProxy || configuredTarget\n ? undefined\n : await (() => {\n const existing = tenantTargetPromises.get(resolveTenantTarget);\n if (existing) return existing;\n\n const pending = resolveTenantTarget();\n tenantTargetPromises.set(resolveTenantTarget, pending);\n return pending;\n })();\n const target =\n options?.apiProxyTarget ??\n configuredTarget ??\n tenantTarget ??\n DEFAULT_API_URL;\n const storefrontSubdomain = storefrontSubdomainFromTarget(target);\n\n if (tenantTarget) {\n console.log(`[fluid-portal-dev] Tenant API proxy: ${tenantTarget}`);\n console.log(\n \"[fluid-portal-dev] Member data still requires a portal handoff session; localhost requests may return 401.\",\n );\n } else if (\n !options?.apiProxyTarget &&\n !appDefinesProxy &&\n !configuredTarget\n ) {\n console.warn(\n `[fluid-portal-dev] Could not resolve the company tenant API; falling back to ${DEFAULT_API_URL}. ` +\n \"Built-in member screens may not load. Set VITE_API_URL explicitly or sign in with the project's Fluid profile.\",\n );\n } else if (storefrontSubdomain) {\n console.warn(\n `[fluid-portal-dev] ${target} is the storefront host, not the Portal tenant BFF. ` +\n `Built-in member APIs live at https://${storefrontSubdomain}.portal.fluid.app; remove the override to let the CLI resolve it.`,\n );\n }\n\n // Vite merges a plugin's returned config OVER the user config, so an\n // app's own explicit define / /api proxy is only preserved by checking\n // for it and yielding here. BOTH API-host env vars must be blanked:\n // dev.ts's envPrefix exposes NEXT_PUBLIC_API_BASE_URL to the SPA too,\n // so leaving it defined would recreate the exact cross-origin bypass\n // this hook exists to prevent, just for Next.js-migrated portals.\n const defines: Record<string, string> = {};\n for (const key of [\n \"import.meta.env.VITE_API_URL\",\n \"import.meta.env.NEXT_PUBLIC_API_BASE_URL\",\n ]) {\n if (config.define?.[key] === undefined) {\n defines[key] = JSON.stringify(\"\");\n }\n }\n const proxy = !appDefinesProxy\n ? { \"/api\": { target, changeOrigin: true } }\n : {};\n\n return {\n define: defines,\n server: { proxy },\n };\n },\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n configResolved(config: any) {\n const root: string = config.root ?? process.cwd();\n portalDir = options?.portalDir\n ? resolve(root, options.portalDir)\n : join(root, \"portal\");\n },\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n configureServer(server: any) {\n // Idempotency: `fluid portal dev` injects this plugin, and a portal's\n // own vite.config may also wire it. Only the first instance registers\n // the watcher + middleware so we don't double-reload or double-serve.\n if (server.__fluidPortalDevWired) return;\n server.__fluidPortalDevWired = true;\n\n const watchDir = portalDir;\n\n if (existsSync(watchDir)) {\n server.watcher.add(watchDir);\n\n let reloadTimer: ReturnType<typeof setTimeout> | null = null;\n\n const onFileChange = (filePath: string) => {\n if (!filePath.startsWith(watchDir)) return;\n\n cachedManifest = null;\n buildInFlight = null;\n manifestGeneration += 1;\n\n console.log(\n `[fluid-portal-dev] File changed: ${filePath.replace(watchDir + sep, \"\")}`,\n );\n\n if (reloadTimer) clearTimeout(reloadTimer);\n reloadTimer = setTimeout(() => {\n reloadTimer = null;\n server.ws.send({ type: \"full-reload\", path: \"*\" });\n }, DEBOUNCE_MS);\n };\n\n server.watcher.on(\"change\", onFileChange);\n server.watcher.on(\"add\", onFileChange);\n server.watcher.on(\"unlink\", onFileChange);\n }\n\n // ── Middleware to intercept manifest requests ───────────────────\n // Every MANIFEST_PATHS route returns the SAME `{ manifest }` payload:\n // the portal-tenant BFF route the current SDK runtime fetches\n // (useFluidApp → app_manifest_show) and the legacy FluidOS route, so\n // the local portal/ draft feeds the running app regardless of which\n // runtime generation it uses (the SDK adapter reads\n // `response.manifest`, matching buildManifestFromLocalFiles' output).\n server.middlewares.use(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (req: any, res: any, next: () => void) => {\n const url: string | undefined = req.url;\n\n if (!url || !MANIFEST_PATHS.some((path) => url.includes(path))) {\n next();\n return;\n }\n\n (async () => {\n try {\n if (!existsSync(portalDir)) {\n // Fall through to the Vite proxy so requests reach the real\n // API when local portal content is unavailable (e.g. --skip-pull).\n next();\n return;\n }\n\n let manifestJson = cachedManifest;\n if (manifestJson == null) {\n if (!buildInFlight) {\n // Stamp the build with the generation it was started\n // under. onFileChange bumps that counter, so a build\n // whose inputs changed underneath it can be recognized\n // when it finally resolves.\n const generation = manifestGeneration;\n buildInFlight = buildManifestFromLocalFiles(portalDir)\n .then((m) => {\n const json = JSON.stringify(m);\n // Only a build still current may populate the\n // cache. Caching a superseded one pinned the\n // pre-edit snapshot permanently: a non-null cache\n // means no later request ever rebuilds, so the\n // edit stayed invisible until some unrelated file\n // happened to change outside a build window.\n if (generation === manifestGeneration) {\n cachedManifest = json;\n buildInFlight = null;\n }\n return json;\n })\n .catch((err) => {\n // Same guard: a superseded build must not clear a\n // newer one's handle.\n if (generation === manifestGeneration) {\n buildInFlight = null; // allow retry on next request\n }\n throw err;\n });\n }\n // This response serves what was built for it, which is\n // correct even when superseded — the request predates\n // the edit. The point is that the NEXT one rebuilds.\n manifestJson = await buildInFlight;\n }\n\n res.writeHead(200, {\n \"Content-Type\": \"application/json\",\n \"X-Portal-Dev-Mode\": \"true\",\n \"Cache-Control\": \"no-store\",\n });\n res.end(manifestJson);\n } catch (err) {\n console.error(\"[fluid-portal-dev] Error building manifest:\", err);\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error:\n err instanceof Error\n ? err.message\n : \"Failed to build manifest from local files\",\n }),\n );\n }\n })();\n },\n );\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"portal-dev-plugin-BFqDxRMa.mjs","names":[],"sources":["../src/vite-plugin/portal-dev-plugin.ts"],"sourcesContent":["/**\n * Vite plugin for local portal content development.\n *\n * Intercepts the manifest API request and serves content assembled from the\n * local `portal/` directory. Watches portal files for changes and triggers a\n * full page reload.\n *\n * The manifest is intercepted on BOTH paths the SDK has used across versions\n * (`/api/app/manifest` since portal-sdk 0.1.4xx, `/api/fluid_os/definitions/\n * active` before that) so a newer SDK against an older-generation app — or\n * vice versa — still gets the local draft.\n */\n\nimport { join, resolve, sep } from \"node:path\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { getAuthToken, getFluidApiBase } from \"@fluid-app/fluid-cli\";\nimport { buildManifestFromLocalFiles } from \"./build-manifest.js\";\n\n/** Options for the portal dev plugin. */\nexport interface PortalDevPluginOptions {\n portalDir?: string;\n /**\n * When true (default), dev-server requests are forced same-origin: the\n * plugin blanks `import.meta.env.VITE_API_URL` in serve mode and proxies\n * `/api` to the configured Fluid host instead. Without this, a `.env`\n * pointing VITE_API_URL at a remote API makes the SPA fetch its manifest\n * cross-origin — silently bypassing this plugin and rendering the remote\n * app instead of the local `portal/` draft. Set false to opt out and let\n * the SPA call the remote API directly.\n */\n sameOriginDev?: boolean;\n /**\n * Override the `/api` dev-proxy target. Defaults to VITE_API_URL from the\n * process env / .env files, then the authenticated company's\n * `<subdomain>.portal.fluid.app` tenant BFF, then https://api.fluid.app.\n */\n apiProxyTarget?: string;\n /**\n * Override tenant-target discovery. Primarily useful to keep embedded plugin\n * integrations and tests deterministic.\n */\n resolveTenantApiTarget?: () => Promise<string | undefined>;\n}\n\nconst DEBOUNCE_MS = 100;\n\n/** Manifest endpoints across SDK generations — all serve the local draft. */\nconst MANIFEST_PATHS = [\n \"/api/app/manifest\",\n \"/api/fluid_os/definitions/active\",\n];\n\nconst DEFAULT_API_URL = \"https://api.fluid.app\";\nconst TENANT_LOOKUP_TIMEOUT_MS = 3_000;\nconst tenantTargetPromises = new WeakMap<\n () => Promise<string | undefined>,\n Promise<string | undefined>\n>();\n\ninterface CompanyMeResponse {\n data?: {\n company?: {\n subdomain?: unknown;\n };\n };\n}\n\nexport interface TenantApiTargetDependencies {\n token?: string | null;\n apiBase?: string;\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n}\n\n/**\n * Resolve the portal tenant BFF for the CLI's project-aware Fluid profile.\n *\n * Portal member APIs do not live on api.fluid.app or `<tenant>.fluid.app`.\n * Their OpenAPI server is `<tenant>.portal.fluid.app`, and using either of\n * the former hosts produces a wall of unrelated 404s in otherwise-valid\n * local portals.\n */\nexport async function resolvePortalTenantApiTarget(\n dependencies: TenantApiTargetDependencies = {},\n): Promise<string | undefined> {\n const token =\n dependencies.token !== undefined ? dependencies.token : getAuthToken();\n if (!token) return undefined;\n\n const controller = new AbortController();\n const timer = setTimeout(\n () => controller.abort(),\n dependencies.timeoutMs ?? TENANT_LOOKUP_TIMEOUT_MS,\n );\n\n try {\n const response = await (dependencies.fetchImpl ?? fetch)(\n `${(dependencies.apiBase ?? getFluidApiBase()).replace(/\\/+$/, \"\")}/api/company/v1/companies/me`,\n {\n headers: {\n Authorization: `Bearer ${token}`,\n Accept: \"application/json\",\n },\n signal: controller.signal,\n },\n );\n if (!response.ok) return undefined;\n\n const body = (await response.json()) as CompanyMeResponse;\n const subdomain = body.data?.company?.subdomain;\n if (\n typeof subdomain !== \"string\" ||\n !/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(subdomain)\n ) {\n return undefined;\n }\n\n return `https://${subdomain}.portal.fluid.app`;\n } catch {\n return undefined;\n } finally {\n clearTimeout(timer);\n }\n}\n\n/**\n * Fallback .env reader for VITE_API_URL, used only when vite's `loadEnv`\n * can't be imported (it's a declared dependency, so this is defensive — but\n * a broken install must degrade to \"wrong host\" rather than \"dev server\n * won't boot\"). Mirrors the basic lookup order: live env > .env.local >\n * .env. Unlike loadEnv it ignores .env.[mode] files and variable expansion.\n */\nfunction readViteApiUrlFallback(root: string): string | undefined {\n if (process.env.VITE_API_URL) return process.env.VITE_API_URL;\n if (process.env.NEXT_PUBLIC_API_BASE_URL) {\n return process.env.NEXT_PUBLIC_API_BASE_URL;\n }\n for (const file of [\".env.local\", \".env\"]) {\n const path = join(root, file);\n if (!existsSync(path)) continue;\n for (const line of readFileSync(path, \"utf8\").split(\"\\n\")) {\n // Quoted values stop at the closing `\"`; unquoted values stop before\n // an inline ` # comment` tail (dotenv semantics — a trailing comment\n // must not leak into the proxy target URL).\n const match =\n /^\\s*VITE_API_URL\\s*=\\s*(?:\"([^\"]*)\"|(.*?))\\s*(?:#.*)?$/.exec(line);\n const value = match?.[1] ?? match?.[2];\n if (value) return value;\n }\n }\n return undefined;\n}\n\nfunction storefrontSubdomainFromTarget(target: string): string | undefined {\n try {\n const hostname = new URL(target).hostname;\n const match = /^([a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\\.fluid\\.app$/.exec(\n hostname,\n );\n const subdomain = match?.[1];\n if (\n !subdomain ||\n [\"admin\", \"api\", \"app\", \"docs\", \"portal\", \"upload\"].includes(subdomain)\n ) {\n return undefined;\n }\n return subdomain;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Resolve VITE_API_URL the way vite itself would — `loadEnv` honors\n * .env.[mode], .env.[mode].local, envDir, and variable expansion, which the\n * fallback parser does not (a mode-specific staging API must not silently\n * fall back to production).\n */\nasync function resolveViteApiUrl(\n root: string,\n mode: string,\n envDir: string | undefined,\n): Promise<string | undefined> {\n try {\n const { loadEnv } = await import(\"vite\");\n const env = loadEnv(mode, envDir ?? root, [\"VITE_\", \"NEXT_PUBLIC_\"]);\n return (\n env.VITE_API_URL ||\n process.env.VITE_API_URL ||\n // Portals migrated from Next.js conventions configure the API host as\n // NEXT_PUBLIC_API_BASE_URL — honored by `fluid portal dev` since it\n // was introduced, so it stays a recognized source here.\n env.NEXT_PUBLIC_API_BASE_URL ||\n process.env.NEXT_PUBLIC_API_BASE_URL ||\n undefined\n );\n } catch {\n return readViteApiUrlFallback(root);\n }\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function portalDevPlugin(options?: PortalDevPluginOptions): any {\n let portalDir: string;\n let cachedManifest: string | null = null;\n let buildInFlight: Promise<string> | null = null;\n /** Bumped on every watched file change. A build carries the value it\n * started under; if it no longer matches when the build resolves, the\n * build read pre-edit state and must not be cached. */\n let manifestGeneration = 0;\n const resolveTenantTarget =\n options?.resolveTenantApiTarget ?? resolvePortalTenantApiTarget;\n\n return {\n name: \"fluid-portal-dev\",\n enforce: \"pre\" as const,\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async config(config: any, env: any) {\n if (env?.command !== \"serve\" || options?.sameOriginDev === false) {\n return {};\n }\n\n const root: string = config.root ?? process.cwd();\n const appDefinesProxy = config.server?.proxy?.[\"/api\"] !== undefined;\n const configuredTarget =\n options?.apiProxyTarget || appDefinesProxy\n ? undefined\n : await resolveViteApiUrl(\n root,\n env?.mode ?? \"development\",\n config.envDir,\n );\n const tenantTarget =\n options?.apiProxyTarget || appDefinesProxy || configuredTarget\n ? undefined\n : await (() => {\n const existing = tenantTargetPromises.get(resolveTenantTarget);\n if (existing) return existing;\n\n const pending = resolveTenantTarget();\n tenantTargetPromises.set(resolveTenantTarget, pending);\n return pending;\n })();\n const target =\n options?.apiProxyTarget ??\n configuredTarget ??\n tenantTarget ??\n DEFAULT_API_URL;\n const storefrontSubdomain = storefrontSubdomainFromTarget(target);\n\n if (tenantTarget) {\n console.log(`[fluid-portal-dev] Tenant API proxy: ${tenantTarget}`);\n console.log(\n \"[fluid-portal-dev] Member data still requires a portal handoff session; localhost requests may return 401.\",\n );\n } else if (\n !options?.apiProxyTarget &&\n !appDefinesProxy &&\n !configuredTarget\n ) {\n console.warn(\n `[fluid-portal-dev] Could not resolve the company tenant API; falling back to ${DEFAULT_API_URL}. ` +\n \"Built-in member screens may not load. Set VITE_API_URL explicitly or sign in with the project's Fluid profile.\",\n );\n } else if (storefrontSubdomain) {\n console.warn(\n `[fluid-portal-dev] ${target} is the storefront host, not the Portal tenant BFF. ` +\n `Built-in member APIs live at https://${storefrontSubdomain}.portal.fluid.app; remove the override to let the CLI resolve it.`,\n );\n }\n\n // Vite merges a plugin's returned config OVER the user config, so an\n // app's own explicit define / /api proxy is only preserved by checking\n // for it and yielding here. BOTH API-host env vars must be blanked:\n // dev.ts's envPrefix exposes NEXT_PUBLIC_API_BASE_URL to the SPA too,\n // so leaving it defined would recreate the exact cross-origin bypass\n // this hook exists to prevent, just for Next.js-migrated portals.\n const defines: Record<string, string> = {};\n for (const key of [\n \"import.meta.env.VITE_API_URL\",\n \"import.meta.env.NEXT_PUBLIC_API_BASE_URL\",\n ]) {\n if (config.define?.[key] === undefined) {\n defines[key] = JSON.stringify(\"\");\n }\n }\n const proxy = !appDefinesProxy\n ? { \"/api\": { target, changeOrigin: true } }\n : {};\n\n return {\n define: defines,\n server: { proxy },\n };\n },\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n configResolved(config: any) {\n const root: string = config.root ?? process.cwd();\n portalDir = options?.portalDir\n ? resolve(root, options.portalDir)\n : join(root, \"portal\");\n },\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n configureServer(server: any) {\n // Idempotency: `fluid portal dev` injects this plugin, and a portal's\n // own vite.config may also wire it. Only the first instance registers\n // the watcher + middleware so we don't double-reload or double-serve.\n if (server.__fluidPortalDevWired) return;\n server.__fluidPortalDevWired = true;\n\n const watchDir = portalDir;\n\n // Registered unconditionally: `portal/` need not exist when the server\n // boots. `fluid portal dev --skip-pull` is exactly that case, and the\n // manifest middleware below re-checks existence per request, so it\n // starts serving local content the moment the directory appears.\n // Gating the watcher on startup existence left that flow serving the\n // very first build forever — no invalidation, no reload, no error.\n server.watcher.add(watchDir);\n\n let reloadTimer: ReturnType<typeof setTimeout> | null = null;\n\n const watchDirPrefix = watchDir.endsWith(sep) ? watchDir : watchDir + sep;\n\n const onFileChange = (filePath: string) => {\n // A separator boundary is required. A bare prefix test also matches\n // siblings that merely start with the same characters, so editing\n // `<root>/portal-backup/x.json` or `<root>/portal.config.ts` used to\n // drop the manifest cache and force a full page reload.\n if (filePath !== watchDir && !filePath.startsWith(watchDirPrefix)) {\n return;\n }\n\n cachedManifest = null;\n buildInFlight = null;\n manifestGeneration += 1;\n\n console.log(\n `[fluid-portal-dev] File changed: ${filePath.replace(watchDirPrefix, \"\")}`,\n );\n\n if (reloadTimer) clearTimeout(reloadTimer);\n reloadTimer = setTimeout(() => {\n reloadTimer = null;\n server.ws.send({ type: \"full-reload\", path: \"*\" });\n }, DEBOUNCE_MS);\n };\n\n server.watcher.on(\"change\", onFileChange);\n server.watcher.on(\"add\", onFileChange);\n server.watcher.on(\"unlink\", onFileChange);\n\n // ── Middleware to intercept manifest requests ───────────────────\n // Every MANIFEST_PATHS route returns the SAME `{ manifest }` payload:\n // the portal-tenant BFF route the current SDK runtime fetches\n // (useFluidApp → app_manifest_show) and the legacy FluidOS route, so\n // the local portal/ draft feeds the running app regardless of which\n // runtime generation it uses (the SDK adapter reads\n // `response.manifest`, matching buildManifestFromLocalFiles' output).\n server.middlewares.use(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (req: any, res: any, next: () => void) => {\n const url: string | undefined = req.url;\n\n if (!url || !MANIFEST_PATHS.some((path) => url.includes(path))) {\n next();\n return;\n }\n\n (async () => {\n try {\n if (!existsSync(portalDir)) {\n // Fall through to the Vite proxy so requests reach the real\n // API when local portal content is unavailable (e.g. --skip-pull).\n next();\n return;\n }\n\n let manifestJson = cachedManifest;\n if (manifestJson == null) {\n if (!buildInFlight) {\n // Stamp the build with the generation it was started\n // under. onFileChange bumps that counter, so a build\n // whose inputs changed underneath it can be recognized\n // when it finally resolves.\n const generation = manifestGeneration;\n buildInFlight = buildManifestFromLocalFiles(portalDir)\n .then((m) => {\n const json = JSON.stringify(m);\n // Only a build still current may populate the\n // cache. Caching a superseded one pinned the\n // pre-edit snapshot permanently: a non-null cache\n // means no later request ever rebuilds, so the\n // edit stayed invisible until some unrelated file\n // happened to change outside a build window.\n if (generation === manifestGeneration) {\n cachedManifest = json;\n buildInFlight = null;\n }\n return json;\n })\n .catch((err) => {\n // Same guard: a superseded build must not clear a\n // newer one's handle.\n if (generation === manifestGeneration) {\n buildInFlight = null; // allow retry on next request\n }\n throw err;\n });\n }\n // This response serves what was built for it, which is\n // correct even when superseded — the request predates\n // the edit. The point is that the NEXT one rebuilds.\n manifestJson = await buildInFlight;\n }\n\n res.writeHead(200, {\n \"Content-Type\": \"application/json\",\n \"X-Portal-Dev-Mode\": \"true\",\n \"Cache-Control\": \"no-store\",\n });\n res.end(manifestJson);\n } catch (err) {\n console.error(\"[fluid-portal-dev] Error building manifest:\", err);\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error:\n err instanceof Error\n ? err.message\n : \"Failed to build manifest from local files\",\n }),\n );\n }\n })();\n },\n );\n },\n };\n}\n"],"mappings":"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"}
|
package/dist/{portal-widget-dev-plugin-CO-im-5P.mjs → portal-widget-dev-plugin-Dis7d954.mjs}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { N as __exportAll } from "./pull-
|
|
1
|
+
import { N as __exportAll } from "./pull-Kx1ncTLF.mjs";
|
|
2
2
|
import { c as fluidWidgetDevPlugin, l as handleOptions, u as setCorsHeaders } from "./src-D1cU2gmw.mjs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { existsSync } from "node:fs";
|
|
@@ -143,4 +143,4 @@ if (widgetPackage) {
|
|
|
143
143
|
//#endregion
|
|
144
144
|
export { portal_widget_dev_plugin_exports as n, portalWidgetDevPlugin as t };
|
|
145
145
|
|
|
146
|
-
//# sourceMappingURL=portal-widget-dev-plugin-
|
|
146
|
+
//# sourceMappingURL=portal-widget-dev-plugin-Dis7d954.mjs.map
|
package/dist/{portal-widget-dev-plugin-CO-im-5P.mjs.map → portal-widget-dev-plugin-Dis7d954.mjs.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"portal-widget-dev-plugin-
|
|
1
|
+
{"version":3,"file":"portal-widget-dev-plugin-Dis7d954.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"}
|
|
@@ -14548,7 +14548,10 @@ const generatedSchemas = {
|
|
|
14548
14548
|
}],
|
|
14549
14549
|
title: "Background",
|
|
14550
14550
|
description: "Background for the text container",
|
|
14551
|
-
default:
|
|
14551
|
+
default: {
|
|
14552
|
+
type: "solid",
|
|
14553
|
+
color: "background"
|
|
14554
|
+
}
|
|
14552
14555
|
},
|
|
14553
14556
|
padding: {
|
|
14554
14557
|
enum: [
|
|
@@ -14747,7 +14750,10 @@ const generatedSchemas = {
|
|
|
14747
14750
|
}],
|
|
14748
14751
|
title: "Background",
|
|
14749
14752
|
description: "Background for the list container",
|
|
14750
|
-
default:
|
|
14753
|
+
default: {
|
|
14754
|
+
type: "solid",
|
|
14755
|
+
color: "background"
|
|
14756
|
+
}
|
|
14751
14757
|
},
|
|
14752
14758
|
padding: {
|
|
14753
14759
|
enum: [
|
|
@@ -14913,7 +14919,10 @@ const generatedSchemas = {
|
|
|
14913
14919
|
}],
|
|
14914
14920
|
title: "Background",
|
|
14915
14921
|
description: "Background for the calendar container",
|
|
14916
|
-
default:
|
|
14922
|
+
default: {
|
|
14923
|
+
type: "solid",
|
|
14924
|
+
color: "background"
|
|
14925
|
+
}
|
|
14917
14926
|
},
|
|
14918
14927
|
textColor: {
|
|
14919
14928
|
enum: [
|
|
@@ -15183,7 +15192,10 @@ const generatedSchemas = {
|
|
|
15183
15192
|
}],
|
|
15184
15193
|
title: "Background",
|
|
15185
15194
|
description: "Background for the card",
|
|
15186
|
-
default:
|
|
15195
|
+
default: {
|
|
15196
|
+
type: "solid",
|
|
15197
|
+
color: "background"
|
|
15198
|
+
}
|
|
15187
15199
|
},
|
|
15188
15200
|
padding: {
|
|
15189
15201
|
enum: [
|
|
@@ -15639,7 +15651,10 @@ const generatedSchemas = {
|
|
|
15639
15651
|
}],
|
|
15640
15652
|
title: "Background",
|
|
15641
15653
|
description: "Background for the container",
|
|
15642
|
-
default:
|
|
15654
|
+
default: {
|
|
15655
|
+
type: "solid",
|
|
15656
|
+
color: "background"
|
|
15657
|
+
}
|
|
15643
15658
|
},
|
|
15644
15659
|
textColor: {
|
|
15645
15660
|
enum: [
|
|
@@ -15910,7 +15925,10 @@ const generatedSchemas = {
|
|
|
15910
15925
|
}],
|
|
15911
15926
|
title: "Background",
|
|
15912
15927
|
description: "Background for the chart container",
|
|
15913
|
-
default:
|
|
15928
|
+
default: {
|
|
15929
|
+
type: "solid",
|
|
15930
|
+
color: "background"
|
|
15931
|
+
}
|
|
15914
15932
|
},
|
|
15915
15933
|
padding: {
|
|
15916
15934
|
enum: [
|
|
@@ -16069,7 +16087,10 @@ const generatedSchemas = {
|
|
|
16069
16087
|
}],
|
|
16070
16088
|
title: "Background",
|
|
16071
16089
|
description: "Background for the container",
|
|
16072
|
-
default:
|
|
16090
|
+
default: {
|
|
16091
|
+
type: "solid",
|
|
16092
|
+
color: "background"
|
|
16093
|
+
}
|
|
16073
16094
|
},
|
|
16074
16095
|
children: {
|
|
16075
16096
|
type: "array",
|
|
@@ -16529,7 +16550,10 @@ const generatedSchemas = {
|
|
|
16529
16550
|
}],
|
|
16530
16551
|
title: "Background",
|
|
16531
16552
|
description: "Background for the layout container",
|
|
16532
|
-
default:
|
|
16553
|
+
default: {
|
|
16554
|
+
type: "solid",
|
|
16555
|
+
color: "background"
|
|
16556
|
+
}
|
|
16533
16557
|
},
|
|
16534
16558
|
padding: {
|
|
16535
16559
|
enum: [
|
|
@@ -16990,7 +17014,10 @@ const generatedSchemas = {
|
|
|
16990
17014
|
}],
|
|
16991
17015
|
title: "Background",
|
|
16992
17016
|
description: "Background color or image for the widget",
|
|
16993
|
-
default:
|
|
17017
|
+
default: {
|
|
17018
|
+
type: "solid",
|
|
17019
|
+
color: "background"
|
|
17020
|
+
}
|
|
16994
17021
|
},
|
|
16995
17022
|
listType: {
|
|
16996
17023
|
enum: ["unordered", "ordered"],
|
|
@@ -17351,7 +17378,10 @@ const generatedSchemas = {
|
|
|
17351
17378
|
}],
|
|
17352
17379
|
title: "Background",
|
|
17353
17380
|
description: "Background for the widget container",
|
|
17354
|
-
default:
|
|
17381
|
+
default: {
|
|
17382
|
+
type: "solid",
|
|
17383
|
+
color: "background"
|
|
17384
|
+
}
|
|
17355
17385
|
},
|
|
17356
17386
|
textColor: {
|
|
17357
17387
|
enum: [
|
|
@@ -17640,7 +17670,10 @@ const generatedSchemas = {
|
|
|
17640
17670
|
}],
|
|
17641
17671
|
title: "Background",
|
|
17642
17672
|
description: "Background color for nested media container",
|
|
17643
|
-
default:
|
|
17673
|
+
default: {
|
|
17674
|
+
type: "solid",
|
|
17675
|
+
color: "background"
|
|
17676
|
+
}
|
|
17644
17677
|
},
|
|
17645
17678
|
shareables: {
|
|
17646
17679
|
$ref: "#/$defs/jsonValue",
|
|
@@ -17773,7 +17806,10 @@ const generatedSchemas = {
|
|
|
17773
17806
|
}],
|
|
17774
17807
|
title: "Background",
|
|
17775
17808
|
description: "Background for the widget",
|
|
17776
|
-
default:
|
|
17809
|
+
default: {
|
|
17810
|
+
type: "solid",
|
|
17811
|
+
color: "background"
|
|
17812
|
+
}
|
|
17777
17813
|
},
|
|
17778
17814
|
textColor: {
|
|
17779
17815
|
enum: [
|
|
@@ -18488,7 +18524,10 @@ const generatedSchemas = {
|
|
|
18488
18524
|
}],
|
|
18489
18525
|
title: "Background",
|
|
18490
18526
|
description: "Background for the widget container",
|
|
18491
|
-
default:
|
|
18527
|
+
default: {
|
|
18528
|
+
type: "solid",
|
|
18529
|
+
color: "background"
|
|
18530
|
+
}
|
|
18492
18531
|
},
|
|
18493
18532
|
textColor: {
|
|
18494
18533
|
enum: [
|
|
@@ -18897,7 +18936,10 @@ const generatedSchemas = {
|
|
|
18897
18936
|
}],
|
|
18898
18937
|
title: "Background",
|
|
18899
18938
|
description: "Background for the widget container",
|
|
18900
|
-
default:
|
|
18939
|
+
default: {
|
|
18940
|
+
type: "solid",
|
|
18941
|
+
color: "background"
|
|
18942
|
+
}
|
|
18901
18943
|
},
|
|
18902
18944
|
textColor: {
|
|
18903
18945
|
enum: [
|
|
@@ -19192,7 +19234,10 @@ const generatedSchemas = {
|
|
|
19192
19234
|
}],
|
|
19193
19235
|
title: "Background",
|
|
19194
19236
|
description: "Container background",
|
|
19195
|
-
default:
|
|
19237
|
+
default: {
|
|
19238
|
+
type: "solid",
|
|
19239
|
+
color: "background"
|
|
19240
|
+
}
|
|
19196
19241
|
},
|
|
19197
19242
|
padding: {
|
|
19198
19243
|
enum: [
|
|
@@ -19406,7 +19451,10 @@ const generatedSchemas = {
|
|
|
19406
19451
|
}],
|
|
19407
19452
|
title: "Background",
|
|
19408
19453
|
description: "Background for the table container",
|
|
19409
|
-
default:
|
|
19454
|
+
default: {
|
|
19455
|
+
type: "solid",
|
|
19456
|
+
color: "background"
|
|
19457
|
+
}
|
|
19410
19458
|
},
|
|
19411
19459
|
alternatingColorEnabled: {
|
|
19412
19460
|
type: "boolean",
|
|
@@ -19726,7 +19774,10 @@ const generatedSchemas = {
|
|
|
19726
19774
|
}],
|
|
19727
19775
|
title: "Background",
|
|
19728
19776
|
description: "Background for the text container",
|
|
19729
|
-
default:
|
|
19777
|
+
default: {
|
|
19778
|
+
type: "solid",
|
|
19779
|
+
color: "background"
|
|
19780
|
+
}
|
|
19730
19781
|
},
|
|
19731
19782
|
padding: {
|
|
19732
19783
|
enum: [
|
|
@@ -19879,7 +19930,10 @@ const generatedSchemas = {
|
|
|
19879
19930
|
}],
|
|
19880
19931
|
title: "Background",
|
|
19881
19932
|
description: "Background for the widget container",
|
|
19882
|
-
default:
|
|
19933
|
+
default: {
|
|
19934
|
+
type: "solid",
|
|
19935
|
+
color: "background"
|
|
19936
|
+
}
|
|
19883
19937
|
},
|
|
19884
19938
|
textColor: {
|
|
19885
19939
|
enum: [
|
|
@@ -21073,4 +21127,4 @@ const pullCommand = new Command("pull").description("Pull a Fluid OS definition'
|
|
|
21073
21127
|
//#endregion
|
|
21074
21128
|
export { toFluidOsDynamicObject as A, resolveIdToSlug as C, atomicWriteFile as D, writeMappings as E, ApiError as M, __exportAll as N, createFluidOsClient as O, removeMapping as S, updateMapping as T, diffAgainstSnapshot as _, buildNavigationIdToSlugMap as a, deriveSlug as b, transformNavigation as c, transformScreen as d, transformTheme as f, computeFileHash as g, collectSnapshotNetworkWidgetGrants as h, buildIdToSlugMap as i, createFluidOsHeyApiClient as j, fluidOsApi as k, transformNavigationItems as l, collectNetworkWidgetGrants as m, pull_exports as n, buildThemeIdToSlugMap as o, buildSnapshot as p, validatePortalResource as r, deriveScreenSlug as s, pullCommand as t, transformProfile as u, readSnapshot as v, resolveSlugToId as w, readMappings as x, writeSnapshot as y };
|
|
21075
21129
|
|
|
21076
|
-
//# sourceMappingURL=pull-
|
|
21130
|
+
//# sourceMappingURL=pull-Kx1ncTLF.mjs.map
|