@fluid-app/fluid-cli-portal 0.1.33 → 0.1.34
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.mjs +1211 -24
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["_currentDir","PORTAL_DIR","TSX_CLI_PATH","createTempDirectory","isRecord","path","isRecord","readPortalFile","PORTAL_SYNC_DIR","createClient","fluidOs.fluid_os_v0_create_fluid_osscreen","fluidOs.fluid_os_v0_update_fluid_osscreen","fluidOs.fluid_os_v0_delete_fluid_osscreen","fluidOs.fluid_os_v0_create_fluid_ostheme","fluidOs.fluid_os_v0_update_fluid_ostheme","fluidOs.fluid_os_v0_delete_fluid_ostheme","fluidOs.fluid_os_v0_create_fluid_osnavigation","fluidOs.fluid_os_v0_create_fluid_osnavigation_item","fluidOs.fluid_os_v0_update_fluid_osnavigation","fluidOs.fluid_os_v0_list_fluid_osnavigation_items","fluidOs.fluid_os_v0_delete_fluid_osnavigation_item","fluidOs.fluid_os_v0_update_fluid_osnavigation_item","fluidOs.fluid_os_v0_delete_fluid_osnavigation","fluidOs.fluid_os_v0_create_fluid_osprofile","fluidOs.fluid_os_v0_update_fluid_osprofile","fluidOs.fluid_os_v0_delete_fluid_osprofile","toPosixPath","isRecord","isRecord","fluidOs.fluid_os_v0_create_widget_package_version","fluidOs.fluid_os_v0_complete_widget_package_version_upload","isRecord","DEFAULT_OUT_DIR","fluidOs.fluid_os_v0_create_fluid_osversion","fluidOs.fluid_os_v0_update_fluid_osversion","fluidOs.fluid_os_v0_list_fluid_osversions"],"sources":["../src/types.ts","../src/utils/prompts.ts","../src/utils/file-system.ts","../src/utils/package-manager.ts","../src/commands/create.ts","../src/commands/dev.ts","../src/utils/widget-package-config.ts","../src/utils/extract-manifests.ts","../src/commands/build.ts","../src/utils/push-validation.ts","../src/commands/push.ts","../src/utils/widget-helpers.ts","../src/commands/widget-create.ts","../src/utils/widget-package-artifacts.ts","../src/utils/widget-package-validation.ts","../src/utils/widget-package-builder.ts","../src/utils/widget-package-upload.ts","../src/commands/widget-package-publish.ts","../src/commands/deploy.ts","../src/commands/doctor.ts","../src/commands/version.ts","../src/commands/widget-publish.ts","../src/index.ts"],"sourcesContent":["// ─────────────────────────────────────────────────────────────────────────────\n// Template types - derived from const object\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Available project templates\n */\nexport const TEMPLATES = {\n starter: \"starter\",\n} as const;\n\n/**\n * Union type of valid template names\n */\nexport type TemplateName = (typeof TEMPLATES)[keyof typeof TEMPLATES];\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Project configuration types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Selected page template info\n */\nexport interface SelectedPageTemplate {\n readonly id: string;\n readonly slug: string;\n readonly name: string;\n}\n\n/**\n * Configuration options collected during project scaffolding\n */\nexport interface ProjectConfig {\n /** Project name (used for directory and package.json name) */\n readonly name: string;\n /** Whether to install dependencies after scaffolding */\n readonly installDeps: boolean;\n /** Selected optional page templates to include */\n readonly selectedPages: readonly SelectedPageTemplate[];\n /** CLI profile name for .fluidrc (empty string if none selected) */\n readonly profileName: string;\n}\n\n/**\n * Options for the create command (from CLI arguments)\n */\nexport interface CreateOptions {\n /** Skip dependency installation */\n readonly skipInstall?: boolean;\n /** Directory to create the project in (defaults to cwd) */\n readonly outputDir?: string;\n /** Use local monorepo packages via file: links instead of npm versions */\n readonly local?: boolean;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Command option types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Options for the dev command\n */\nexport interface DevOptions {\n readonly port?: number;\n readonly host?: boolean;\n}\n\n/**\n * Options for the build command\n */\nexport interface BuildOptions {\n readonly outDir?: string;\n}\n\n/**\n * Options for the widget create command\n */\nexport interface WidgetCreateOptions {\n /** Category for palette grouping */\n readonly category?: string;\n}\n\n/**\n * Options for the portal deploy command\n */\nexport interface PortalDeployOptions {\n readonly environment?: string;\n readonly outDir?: string;\n readonly dryRun?: boolean;\n}\n\n/**\n * Options for the top-level widget publish command\n */\nexport interface WidgetPublishOptions {\n readonly droplet: string;\n readonly outDir?: string;\n readonly dryRun?: boolean;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Template processing types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Template variables for Handlebars processing\n */\nexport interface TemplateVariables {\n readonly projectName: string;\n readonly sdkVersion: string;\n /** portal-core link used only for --local scaffolds */\n readonly localCoreVersion?: string;\n /** CLI package version (versioned independently from the SDK) */\n readonly cliVersion: string;\n /** Selected page templates for the project */\n readonly selectedPages: readonly SelectedPageTemplate[];\n /** Whether any optional pages were selected */\n readonly hasSelectedPages: boolean;\n /** CLI profile name for .fluidrc */\n readonly profileName: string;\n}\n","import { getActiveProfile, listProfileNames } from \"@fluid-app/fluid-cli\";\nimport prompts from \"prompts\";\nimport {\n type ProjectConfig,\n type CreateOptions,\n type SelectedPageTemplate,\n} from \"../types.js\";\n\n/**\n * Optional page template shape\n */\ninterface OptionalPageTemplate {\n readonly id: string;\n readonly slug: string;\n readonly name: string;\n readonly description: string;\n}\n\n/**\n * Available optional page templates that can be selected during project creation.\n * Core pages (Messaging, Contacts, CRM) are always included automatically.\n */\nconst OPTIONAL_PAGE_TEMPLATES: readonly OptionalPageTemplate[] = [\n // Currently no optional pages - all pages are core\n // Future optional pages can be added here:\n // { id: 'orders', slug: 'orders', name: 'Orders', description: 'Order management page' },\n // { id: 'products', slug: 'products', name: 'Products', description: 'Product catalog page' },\n];\n\n/**\n * Prompts the user for project configuration\n * Pre-fills values from CLI options when provided\n */\nexport async function promptProjectConfig(\n projectName: string,\n options: CreateOptions,\n): Promise<ProjectConfig | null> {\n // Build questions based on what options are missing\n const questions: prompts.PromptObject[] = [];\n\n // Page template selection (only if there are optional templates)\n if (OPTIONAL_PAGE_TEMPLATES.length > 0) {\n questions.push({\n type: \"multiselect\",\n name: \"selectedPages\",\n message: \"Select additional page templates to include\",\n instructions:\n \"\\n Space to select, Enter to confirm. Core pages (Messaging, Contacts, CRM) are always included.\",\n choices: OPTIONAL_PAGE_TEMPLATES.map((page) => ({\n title: page.name,\n value: { id: page.id, slug: page.slug, name: page.name },\n description: page.description,\n })),\n });\n }\n\n // CLI profile for .fluidrc\n const existingProfiles = listProfileNames();\n if (existingProfiles.length > 0) {\n const active = getActiveProfile();\n questions.push({\n type: \"select\",\n name: \"profileName\",\n message: \"CLI profile for this project (.fluidrc)\",\n choices: existingProfiles.map((name) => ({\n title: name === active?.name ? `${name} (active)` : name,\n value: name,\n })),\n });\n }\n\n // Install dependencies\n if (!options.skipInstall) {\n questions.push({\n type: \"confirm\",\n name: \"installDeps\",\n message: \"Install dependencies?\",\n initial: true,\n });\n }\n\n // Non-interactive mode: if stdin is not a TTY and there are remaining\n // prompts, return safe defaults instead of hanging on interactive input.\n if (!process.stdin.isTTY && questions.length > 0) {\n return {\n name: projectName,\n installDeps: false,\n selectedPages: [],\n profileName: getActiveProfile()?.name ?? \"\",\n } satisfies ProjectConfig;\n }\n\n // Fast-path: all options provided via CLI flags, no prompts needed\n if (questions.length === 0) {\n return {\n name: projectName,\n installDeps: options.skipInstall ? false : true,\n selectedPages: [],\n profileName: getActiveProfile()?.name ?? \"\",\n } satisfies ProjectConfig;\n }\n\n // Handle Ctrl+C gracefully\n let cancelled = false;\n const response = await prompts(questions, {\n onCancel: () => {\n cancelled = true;\n return false;\n },\n });\n\n if (cancelled) {\n return null;\n }\n\n // Parse selected pages\n const selectedPages: readonly SelectedPageTemplate[] =\n response.selectedPages ?? [];\n\n return {\n name: projectName,\n installDeps: options.skipInstall ? false : (response.installDeps ?? true),\n selectedPages,\n profileName:\n (response.profileName as string | undefined) ??\n getActiveProfile()?.name ??\n \"\",\n } satisfies ProjectConfig;\n}\n","import type { CliError } from \"@fluid-app/fluid-cli\";\nimport { readdir, readFile, stat, mkdir, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join, dirname, relative } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport Handlebars from \"handlebars\";\nimport type { TemplateVariables } from \"../types.js\";\nimport { type Result, success, failure } from \"@fluid-app/fluid-cli\";\n\nconst _currentFile = fileURLToPath(import.meta.url);\nconst _currentDir = dirname(_currentFile);\n\n/**\n * Find the package root by walking up from the current directory to the nearest package.json.\n * Works whether running from dist/ (bundled) or src/utils/ (tsx dev mode).\n */\nfunction findPackageRoot(): string {\n let dir = _currentDir;\n while (!existsSync(join(dir, \"package.json\"))) {\n const parent = dirname(dir);\n if (parent === dir) throw new Error(\"Could not find package root\");\n dir = parent;\n }\n return dir;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// File system operation error types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Error types for file system operations\n */\nexport const FILE_SYSTEM_ERRORS = {\n directoryNotFound: \"DIRECTORY_NOT_FOUND\",\n fileNotFound: \"FILE_NOT_FOUND\",\n readError: \"READ_ERROR\",\n writeError: \"WRITE_ERROR\",\n templateError: \"TEMPLATE_ERROR\",\n} as const;\n\n/**\n * Union type for file system error codes\n */\nexport type FileSystemErrorCode =\n (typeof FILE_SYSTEM_ERRORS)[keyof typeof FILE_SYSTEM_ERRORS];\n\n/**\n * Structured file system error with code for pattern matching\n */\nexport interface FileSystemError extends CliError {\n readonly code: FileSystemErrorCode;\n readonly message: string;\n readonly path?: string;\n readonly cause?: Error;\n}\n\n/**\n * Create a file system error\n */\nfunction createFsError(\n code: FileSystemErrorCode,\n message: string,\n path?: string,\n cause?: Error,\n): FileSystemError {\n return { code, message, path, cause };\n}\n\n/**\n * Paths for the base + overlay template system\n */\nexport interface TemplatePaths {\n /** Path to shared frontend files used by all templates */\n readonly base: string;\n /** Path to template-specific overlay files */\n readonly overlay: string;\n}\n\n/**\n * Gets paths for the base + overlay template system.\n *\n * The create command copies `base` first, then the `overlay` on top.\n * Any overlay file with the same relative path overwrites the base version.\n */\nexport function getTemplatePaths(templateName: string): TemplatePaths {\n const packageRoot = findPackageRoot();\n const templatesDir = join(packageRoot, \"templates\");\n return {\n base: join(templatesDir, \"base\"),\n overlay: join(templatesDir, templateName),\n };\n}\n\n/**\n * Gets all files in a directory recursively\n */\nasync function getFiles(dir: string, baseDir: string = dir): Promise<string[]> {\n const entries = await readdir(dir, { withFileTypes: true });\n const files: string[] = [];\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n files.push(...(await getFiles(fullPath, baseDir)));\n } else {\n // Return relative path from baseDir\n files.push(fullPath.slice(baseDir.length + 1));\n }\n }\n\n return files;\n}\n\n/**\n * Processes a template file with Handlebars\n * Files ending in .template have the extension removed and content processed\n * Other files are copied as-is\n */\nfunction processTemplate(\n content: string,\n variables: TemplateVariables,\n isTemplate: boolean,\n filePath?: string,\n): string {\n if (!isTemplate) {\n return content;\n }\n\n try {\n const template = Handlebars.compile(content);\n return template(variables);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(\n `Template processing failed${filePath ? ` for ${filePath}` : \"\"}: ${message}`,\n );\n }\n}\n\n/**\n * Gets the output filename for a template file\n * Removes .template extension if present\n */\ninterface TemplateSkillFile {\n readonly relativePath: string;\n readonly content: string;\n}\n\nasync function getSharedTemplateSkillFiles(): Promise<TemplateSkillFile[]> {\n const packageRoot = findFluidCliPackageRoot();\n const skillsRoot = join(packageRoot, \"template-skills\");\n const files = await getFiles(skillsRoot);\n\n return Promise.all(\n files.map(async (file) => ({\n relativePath: join(\"skills\", file),\n content: await readFile(join(skillsRoot, file), \"utf-8\"),\n })),\n );\n}\n\nfunction findFluidCliPackageRoot(): string {\n const workspacePackageRoot = join(findPackageRoot(), \"..\", \"core\");\n if (existsSync(join(workspacePackageRoot, \"template-skills\"))) {\n return workspacePackageRoot;\n }\n\n let dir = dirname(fileURLToPath(import.meta.resolve(\"@fluid-app/fluid-cli\")));\n while (!existsSync(join(dir, \"package.json\"))) {\n const parent = dirname(dir);\n if (parent === dir)\n throw new Error(\"Could not find Fluid CLI package root\");\n dir = parent;\n }\n return dir;\n}\n\nasync function writeOutputFiles(\n targetPath: string,\n outputFiles: readonly string[],\n content: string,\n): Promise<void> {\n for (const outputFile of outputFiles) {\n const destPath = join(targetPath, outputFile);\n const destDir = dirname(destPath);\n await mkdir(destDir, { recursive: true });\n await writeFile(destPath, content, \"utf-8\");\n }\n}\n\nfunction getOutputFilenames(filename: string): string[] {\n const outputFilename = getOutputFilename(filename);\n const normalized = outputFilename.replace(/\\\\/g, \"/\");\n\n if (normalized === \"AGENTS.md\") return [\"AGENTS.md\", \"CLAUDE.md\"];\n\n if (normalized.startsWith(\"skills/\")) {\n return [join(\".agents\", outputFilename), join(\".claude\", outputFilename)];\n }\n\n return [outputFilename];\n}\n\nfunction getOutputFilename(filename: string): string {\n if (filename.endsWith(\".template\")) {\n return filename.slice(0, -\".template\".length);\n }\n return filename;\n}\n\n/**\n * Copies a template directory to the target directory\n * Processes .template files with Handlebars\n */\nexport async function copyTemplate(\n templatePath: string,\n targetPath: string,\n variables: TemplateVariables,\n): Promise<void> {\n const files = await getFiles(templatePath);\n\n for (const file of files) {\n const sourcePath = join(templatePath, file);\n const isTemplate = file.endsWith(\".template\");\n const outputFiles = getOutputFilenames(file);\n\n // Read source file\n const content = await readFile(sourcePath, \"utf-8\");\n\n // Process and write\n const processed = processTemplate(\n content,\n variables,\n isTemplate,\n sourcePath,\n );\n\n for (const outputFile of outputFiles) {\n const destPath = join(targetPath, outputFile);\n const destDir = dirname(destPath);\n await mkdir(destDir, { recursive: true });\n await writeFile(destPath, processed, \"utf-8\");\n }\n }\n\n for (const skillFile of await getSharedTemplateSkillFiles()) {\n await writeOutputFiles(\n targetPath,\n getOutputFilenames(skillFile.relativePath),\n skillFile.content,\n );\n }\n}\n\n/**\n * Checks if a directory exists\n */\nexport async function directoryExists(path: string): Promise<boolean> {\n try {\n const stats = await stat(path);\n return stats.isDirectory();\n } catch {\n return false;\n }\n}\n\n/**\n * Checks if a file exists\n */\nexport async function fileExists(path: string): Promise<boolean> {\n try {\n const stats = await stat(path);\n return stats.isFile();\n } catch {\n return false;\n }\n}\n\n/**\n * Checks if a path exists (file or directory)\n */\nexport async function pathExists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Creates a directory\n */\nexport async function createDirectory(path: string): Promise<void> {\n await mkdir(path, { recursive: true });\n}\n\n/**\n * Reads the SDK version from the workspace package.json\n * Falls back to ^0.1.0 if not found\n */\nexport async function getSdkVersion(): Promise<string> {\n try {\n // Try to read from workspace\n // CLI lives at packages/cli/portal/, SDK at packages/portal/sdk/\n const packageRoot = findPackageRoot();\n const packagesRoot = join(packageRoot, \"..\", \"..\");\n const sdkPackagePath = join(packagesRoot, \"portal\", \"sdk\", \"package.json\");\n\n const content = await readFile(sdkPackagePath, \"utf-8\");\n const pkg = JSON.parse(content) as { version?: string };\n return `^${pkg.version ?? \"0.1.0\"}`;\n } catch {\n // Fallback for when running outside the workspace\n return \"^0.1.0\";\n }\n}\n\n/**\n * Builds a pnpm link: specifier for local scaffolds.\n *\n * link: keeps the dependency pointed at the workspace package source instead of\n * packing only package.json \"files\" entries like file: does. That lets Vite's\n * development export resolve the SDK source and its workspace dependencies.\n */\nexport function getLocalPackageLinkVersion(\n targetPath: string,\n packagePath: string,\n): string {\n const linkPath = (relative(targetPath, packagePath) || \".\").replace(\n /\\\\/g,\n \"/\",\n );\n return `link:${linkPath}`;\n}\n\n/**\n * Reads the CLI core version from the workspace package.json.\n * Falls back to ^0.1.0 if not found.\n *\n * This is separate from getSdkVersion because the CLI and portal SDK\n * are versioned independently.\n */\nexport async function getCliVersion(): Promise<string> {\n try {\n // CLI portal lives at packages/cli/portal/, CLI core at packages/cli/core/\n const packageRoot = findPackageRoot();\n const cliCorePath = join(packageRoot, \"..\", \"core\", \"package.json\");\n\n const content = await readFile(cliCorePath, \"utf-8\");\n const pkg = JSON.parse(content) as { version?: string };\n return `^${pkg.version ?? \"0.1.0\"}`;\n } catch {\n return \"^0.1.0\";\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Result-based variants for type-safe error handling\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Read a file's content with Result-based error handling\n */\nexport async function readFileSafe(\n path: string,\n): Promise<Result<string, FileSystemError>> {\n try {\n const content = await readFile(path, \"utf-8\");\n return success(content);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n return failure(\n createFsError(\n FILE_SYSTEM_ERRORS.readError,\n `Failed to read file: ${path}`,\n path,\n error,\n ),\n );\n }\n}\n\n/**\n * Write content to a file with Result-based error handling\n */\nexport async function writeFileSafe(\n path: string,\n content: string,\n): Promise<Result<void, FileSystemError>> {\n try {\n await writeFile(path, content, \"utf-8\");\n return success(undefined);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n return failure(\n createFsError(\n FILE_SYSTEM_ERRORS.writeError,\n `Failed to write file: ${path}`,\n path,\n error,\n ),\n );\n }\n}\n\n/**\n * Create a directory with Result-based error handling\n */\nexport async function createDirectorySafe(\n path: string,\n): Promise<Result<void, FileSystemError>> {\n try {\n await mkdir(path, { recursive: true });\n return success(undefined);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n return failure(\n createFsError(\n FILE_SYSTEM_ERRORS.writeError,\n `Failed to create directory: ${path}`,\n path,\n error,\n ),\n );\n }\n}\n\n/**\n * Copy a template directory with Result-based error handling\n */\nexport async function copyTemplateSafe(\n templatePath: string,\n targetPath: string,\n variables: Readonly<TemplateVariables>,\n): Promise<Result<void, FileSystemError>> {\n try {\n const files = await getFiles(templatePath);\n\n for (const file of files) {\n const sourcePath = join(templatePath, file);\n const isTemplateFile = file.endsWith(\".template\");\n const outputFiles = getOutputFilenames(file);\n\n // Read source file\n const content = await readFile(sourcePath, \"utf-8\");\n\n // Process and write\n const processed = processTemplate(\n content,\n variables,\n isTemplateFile,\n sourcePath,\n );\n\n for (const outputFile of outputFiles) {\n const destPath = join(targetPath, outputFile);\n const destDir = dirname(destPath);\n await mkdir(destDir, { recursive: true });\n await writeFile(destPath, processed, \"utf-8\");\n }\n }\n\n for (const skillFile of await getSharedTemplateSkillFiles()) {\n await writeOutputFiles(\n targetPath,\n getOutputFilenames(skillFile.relativePath),\n skillFile.content,\n );\n }\n\n return success(undefined);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n return failure(\n createFsError(\n FILE_SYSTEM_ERRORS.templateError,\n `Failed to copy template from ${templatePath} to ${targetPath}`,\n templatePath,\n error,\n ),\n );\n }\n}\n\n/**\n * Get SDK version with Result-based error handling\n * Unlike getSdkVersion, this returns an error instead of a fallback\n */\nexport async function getSdkVersionSafe(): Promise<\n Result<string, FileSystemError>\n> {\n try {\n // CLI lives at packages/cli/portal/, SDK at packages/portal/sdk/\n const packageRoot = findPackageRoot();\n const packagesRoot = join(packageRoot, \"..\", \"..\");\n const sdkPackagePath = join(packagesRoot, \"portal\", \"sdk\", \"package.json\");\n\n const content = await readFile(sdkPackagePath, \"utf-8\");\n const pkg = JSON.parse(content) as { version?: string };\n const version = pkg.version;\n\n if (version === undefined) {\n return failure(\n createFsError(\n FILE_SYSTEM_ERRORS.readError,\n \"SDK package.json does not contain a version field\",\n sdkPackagePath,\n ),\n );\n }\n\n return success(`^${version}`);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n return failure(\n createFsError(\n FILE_SYSTEM_ERRORS.fileNotFound,\n \"Could not find SDK package.json\",\n undefined,\n error,\n ),\n );\n }\n}\n","import { execa } from \"execa\";\n\n/**\n * Returns the install command for pnpm\n */\nexport function getInstallCommand(): string {\n return \"pnpm install\";\n}\n\n/**\n * Returns the run command for pnpm\n */\nexport function getRunCommand(script: string): string {\n return `pnpm run ${script}`;\n}\n\n/**\n * Runs a pnpm command in the specified directory\n */\nexport async function runPackageManager(\n args: string[],\n cwd: string,\n): Promise<void> {\n await execa(\"pnpm\", args, {\n cwd,\n stdio: \"inherit\",\n });\n}\n\n/**\n * Installs dependencies using pnpm\n */\nexport async function installDependencies(cwd: string): Promise<void> {\n await runPackageManager([\"install\"], cwd);\n}\n","import { Command } from \"commander\";\nimport type { PluginContext } from \"@fluid-app/fluid-cli\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { join, dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { copyFile } from \"node:fs/promises\";\nimport type { CreateOptions } from \"../types.js\";\nimport { promptProjectConfig } from \"../utils/prompts.js\";\nimport {\n getTemplatePaths,\n copyTemplate,\n directoryExists,\n createDirectory,\n getSdkVersion,\n getCliVersion,\n fileExists,\n getLocalPackageLinkVersion,\n} from \"../utils/file-system.js\";\nimport {\n installDependencies,\n getRunCommand,\n} from \"../utils/package-manager.js\";\n\nexport const createCommand: Command = new Command(\"create\")\n .description(\"Create a new Fluid portal application\")\n .argument(\"<app-name>\", \"Name of the application to create\")\n .option(\"--skip-install\", \"Skip dependency installation\")\n .option(\n \"-o, --output-dir <dir>\",\n \"Directory to create the project in (defaults to cwd)\",\n )\n .option(\n \"--local\",\n \"Use local monorepo packages via file: links (for development testing)\",\n )\n .action(async (appName: string, options: CreateOptions) => {\n try {\n console.log();\n console.log(chalk.bold(\"Creating a new Fluid portal application\"));\n console.log();\n\n // Validate app name\n if (!/^[a-z0-9-]+$/.test(appName)) {\n console.error(\n chalk.red(\n \"Error: App name must contain only lowercase letters, numbers, and hyphens\",\n ),\n );\n process.exit(1);\n }\n\n // Check if directory already exists\n const targetPath = join(\n resolve(options.outputDir ?? process.cwd()),\n appName,\n );\n if (await directoryExists(targetPath)) {\n console.error(\n chalk.red(`Error: Directory \"${appName}\" already exists`),\n );\n process.exit(1);\n }\n\n // Prompt for configuration\n const config = await promptProjectConfig(appName, options);\n if (!config) {\n console.log();\n console.log(chalk.yellow(\"Cancelled\"));\n process.exit(0);\n }\n\n console.log();\n\n // Get template paths (base + overlay)\n const templatePaths = getTemplatePaths(\"starter\");\n if (!(await directoryExists(templatePaths.base))) {\n console.error(chalk.red(\"Error: Base template not found\"));\n process.exit(1);\n }\n if (!(await directoryExists(templatePaths.overlay))) {\n console.error(chalk.red(\"Error: Starter template not found\"));\n process.exit(1);\n }\n\n // Get package versions (SDK and CLI are versioned independently)\n let sdkVersion: string;\n let localCoreVersion: string | undefined;\n const cliVersion = await getCliVersion();\n const isLocal = !!options.local;\n\n if (isLocal) {\n // Resolve relative file: paths so the generated project is portable\n // within the same monorepo clone (works regardless of absolute location)\n const currentDir = dirname(fileURLToPath(import.meta.url));\n const packageRoot = join(currentDir, \"..\", \"..\");\n const packagesRoot = join(packageRoot, \"..\", \"..\");\n const sdkPath = join(packagesRoot, \"portal\", \"sdk\");\n const corePath = join(packagesRoot, \"portal\", \"core\");\n\n if (\n !(await directoryExists(sdkPath)) ||\n !(await directoryExists(corePath))\n ) {\n console.error(\n chalk.red(\n \"Error: --local requires running from within the fluid-mono monorepo\\n\" +\n \" Could not find packages/portal/sdk or packages/portal/core\",\n ),\n );\n process.exit(1);\n }\n\n sdkVersion = getLocalPackageLinkVersion(targetPath, sdkPath);\n localCoreVersion = getLocalPackageLinkVersion(targetPath, corePath);\n console.log(chalk.cyan(\" Using local packages (--local mode)\"));\n } else {\n sdkVersion = await getSdkVersion();\n }\n\n // Create project directory\n const spinner = ora(\"Creating project directory...\").start();\n try {\n await createDirectory(targetPath);\n spinner.succeed(\"Created project directory\");\n } catch (error) {\n spinner.fail(\"Failed to create project directory\");\n throw error;\n }\n\n // Copy base template first, then overlay template-specific files on top\n const templateVariables = {\n projectName: config.name,\n sdkVersion,\n localCoreVersion,\n cliVersion,\n selectedPages: config.selectedPages,\n hasSelectedPages: config.selectedPages.length > 0,\n profileName: config.profileName,\n };\n\n spinner.start(\"Copying template files...\");\n try {\n await copyTemplate(templatePaths.base, targetPath, templateVariables);\n await copyTemplate(\n templatePaths.overlay,\n targetPath,\n templateVariables,\n );\n\n // Copy .env.example → .env so dotenv works out of the box\n const envExamplePath = join(targetPath, \".env.example\");\n if (await fileExists(envExamplePath)) {\n await copyFile(envExamplePath, join(targetPath, \".env\"));\n }\n\n spinner.succeed(\"Copied template files\");\n } catch (error) {\n spinner.fail(\"Failed to copy template files\");\n throw error;\n }\n\n // Install dependencies\n if (config.installDeps) {\n spinner.start(\"Installing dependencies with pnpm...\");\n try {\n await installDependencies(targetPath);\n spinner.succeed(\"Installed dependencies\");\n } catch {\n spinner.fail(\"Failed to install dependencies\");\n console.log();\n console.log(\n chalk.yellow(\"You can try installing dependencies manually:\"),\n );\n console.log(chalk.cyan(` cd ${appName}`));\n console.log(chalk.cyan(\" pnpm install\"));\n }\n }\n\n // Print success message\n console.log();\n console.log(\n chalk.green.bold(\"Success!\") + ` Created ${chalk.cyan(appName)}`,\n );\n console.log();\n console.log(\"Next steps:\");\n console.log();\n const cdPath = options.outputDir ? targetPath : appName;\n console.log(chalk.cyan(` cd ${cdPath}`));\n if (!config.installDeps) {\n console.log(chalk.cyan(\" pnpm install\"));\n }\n console.log(chalk.cyan(` ${getRunCommand(\"dev\")}`));\n console.log();\n console.log(\n \"Then open \" +\n chalk.cyan(\"http://localhost:5173\") +\n \" in your browser.\",\n );\n console.log(\n chalk.dim(\n \" (port may differ if 5173 is in use — check the dev server output)\",\n ),\n );\n console.log();\n if (!config.profileName) {\n console.log(\n chalk.yellow(\n \" Run \" +\n chalk.cyan(\"fluid login\") +\n \" and update \" +\n chalk.cyan(\".fluidrc\") +\n \" with your profile name.\",\n ),\n );\n console.log();\n }\n console.log(\n \"Run \" +\n chalk.cyan(\"pnpm pull\") +\n \" and edit \" +\n chalk.cyan(\"portal/\") +\n \" JSON to customize your portal definition.\",\n );\n console.log();\n } catch (error) {\n console.log();\n console.log(\n chalk.red(\"Error:\") +\n \" \" +\n (error instanceof Error ? error.message : String(error)),\n );\n console.log();\n process.exit(1);\n }\n });\n\nexport function registerCreateCommand(ctx: PluginContext): void {\n ctx.program.addCommand(createCommand);\n}\n","/**\n * `fluid portal dev` command\n *\n * Starts the Vite development server with the portal dev plugin,\n * which intercepts manifest API requests and serves content from\n * the local `portal/` directory.\n *\n * If no `portal/` directory exists, prompts the user to run `fluid portal pull`\n * or auto-pulls if they are logged in.\n */\n\nimport { Command } from \"commander\";\nimport type { PluginContext } from \"@fluid-app/fluid-cli\";\nimport chalk from \"chalk\";\nimport { execa } from \"execa\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { DevOptions } from \"../types.js\";\n\nconst PORTAL_DIR = \"portal\";\n\n/**\n * Check if the portal directory exists and has content files.\n * Returns true if at minimum `portal/definition.json` exists.\n */\nfunction hasPortalContent(cwd: string): boolean {\n return existsSync(join(cwd, PORTAL_DIR, \"definition.json\"));\n}\n\n/**\n * Attempt to auto-pull portal content by invoking the pull command's action.\n * Falls back to a helpful error message if pull is not possible.\n */\nasync function autoPull(cwd: string): Promise<boolean> {\n console.log();\n console.log(\n chalk.yellow(\"No portal/ directory found.\") +\n \" Attempting to pull content...\",\n );\n console.log();\n\n try {\n // Dynamically import the pull command to avoid circular deps at module level.\n // Auth is handled internally by the pull command via stored CLI credentials\n // (getAuthToken / getActiveProfile), so no explicit token args are needed.\n // Note: the pull command may call process.exit(1) on failure (e.g. auth\n // errors), which will terminate the process rather than throwing. Use\n // --skip-pull to bypass this if auto-pull causes issues.\n const { pullCommand } = await import(\"./pull.js\");\n\n await pullCommand.parseAsync([], { from: \"user\" });\n\n // Verify content was pulled\n return hasPortalContent(cwd);\n } catch (err) {\n console.log();\n console.log(\n chalk.red(\"Auto-pull failed: \") +\n (err instanceof Error ? err.message : String(err)),\n );\n console.log();\n console.log(\n \"Run \" +\n chalk.cyan(\"fluid portal pull\") +\n \" manually to set up local content.\",\n );\n console.log();\n return false;\n }\n}\n\nexport const devCommand: Command = new Command(\"dev\")\n .description(\"Start the development server with local portal content serving\")\n .option(\"-p, --port <port>\", \"Port to run the dev server on\", \"5173\")\n .option(\"--host\", \"Expose the dev server to the network\")\n .option(\"--skip-pull\", \"Skip auto-pull if portal/ directory is missing\")\n .action(async (options: DevOptions & { skipPull?: boolean }) => {\n const cwd = process.cwd();\n\n // Check if we're in a Fluid project\n const packageJsonPath = join(cwd, \"package.json\");\n if (!existsSync(packageJsonPath)) {\n console.error(\n chalk.red(\"Error: No package.json found in current directory\"),\n );\n console.error(\n chalk.yellow(\"Make sure you're in a Fluid project directory\"),\n );\n process.exit(1);\n }\n\n // Check for vite.config\n const viteConfigPath = join(cwd, \"vite.config.ts\");\n if (!existsSync(viteConfigPath)) {\n console.error(chalk.red(\"Error: No vite.config.ts found\"));\n console.error(\n chalk.yellow(\"This command must be run from a Fluid project directory\"),\n );\n process.exit(1);\n }\n\n // ── Auto-pull check ────────────────────────────────────────────────\n if (!hasPortalContent(cwd) && !options.skipPull) {\n const pulled = await autoPull(cwd);\n if (!pulled) {\n console.error(\n chalk.red(\"Cannot start dev server without portal content.\"),\n );\n console.error(\n chalk.yellow(\n \"Run \" +\n chalk.cyan(\"fluid portal pull\") +\n \" to download content first.\",\n ),\n );\n process.exit(1);\n }\n }\n\n if (hasPortalContent(cwd)) {\n console.log();\n console.log(\n chalk.green(\"Portal dev mode: \") +\n \"local content from \" +\n chalk.cyan(\"portal/\") +\n \" will be served\",\n );\n console.log(\n chalk.gray(\n \" Manifest requests intercepted at /api/fluid_os/definitions/active\",\n ),\n );\n console.log(\n chalk.gray(\" File changes in portal/ will trigger a page reload\"),\n );\n }\n\n // Build vite args\n const viteArgs = [\"vite\"];\n if (options.port) {\n viteArgs.push(\"--port\", String(options.port));\n }\n if (options.host) {\n viteArgs.push(\"--host\");\n }\n\n console.log();\n console.log(chalk.bold(\"Starting development server...\"));\n console.log();\n\n try {\n await execa(\"pnpm\", viteArgs, {\n cwd,\n stdio: \"inherit\",\n });\n } catch (error) {\n // execa v8 sets `signal` (not `code`) when a process is killed by a signal\n const execaError = error as { signal?: string };\n if (execaError.signal === \"SIGINT\") {\n return;\n }\n console.error(chalk.red(\"Development server exited with an error\"));\n process.exit(1);\n }\n });\n\nexport function registerDevCommand(ctx: PluginContext): void {\n ctx.program.addCommand(devCommand);\n}\n","import { execa } from \"execa\";\nimport fs from \"fs-extra\";\nimport { createRequire } from \"node:module\";\nimport path from \"node:path\";\nimport { type Result, success, failure } from \"@fluid-app/fluid-cli\";\n\nconst CONFIG_CANDIDATES = [\n \"src/widgets.config.ts\",\n \"src/portal.config.ts\",\n \"portal.config.ts\",\n] as const;\nconst SOURCE_PACKAGE_EXTRACT_FILENAME = \"extract-widget-packages.ts\";\nconst SOURCE_PACKAGE_OUTPUT_FILENAME = \"source-widget-packages.json\";\nconst SOURCE_PACKAGE_OUTPUT_SENTINEL = \"fluid-widget-source-packages:v1\";\nconst require = createRequire(import.meta.url);\nconst TSX_CLI_PATH = require.resolve(\"tsx/cli\");\n\nexport interface WidgetSourceConfig {\n readonly path: string;\n readonly relativePath: string;\n}\n\nexport interface WidgetSourceConfigLoadError {\n readonly code: \"CONFIG_LOAD_FAILED\" | \"INVALID_FORMAT\";\n readonly message: string;\n readonly details?: string;\n}\n\nexport async function resolvePortalWidgetSourceConfig(\n projectDir: string,\n): Promise<WidgetSourceConfig | undefined> {\n for (const relativePath of CONFIG_CANDIDATES) {\n const candidate = path.join(projectDir, relativePath);\n if (await fs.pathExists(candidate)) {\n return { path: candidate, relativePath };\n }\n }\n\n return undefined;\n}\n\nexport async function loadSourceWidgetPackages(\n projectDir: string,\n): Promise<Result<unknown[], WidgetSourceConfigLoadError>> {\n const config = await resolvePortalWidgetSourceConfig(projectDir);\n if (!config) return success([]);\n\n let tempDir: string | undefined;\n\n try {\n tempDir = await createTempDirectory(projectDir);\n const extractFile = path.join(tempDir, SOURCE_PACKAGE_EXTRACT_FILENAME);\n const outputFile = path.join(tempDir, SOURCE_PACKAGE_OUTPUT_FILENAME);\n\n await fs.writeFile(\n extractFile,\n createSourcePackageExtractorScript({\n projectDir,\n configPath: config.path,\n }),\n { encoding: \"utf-8\", flag: \"wx\" },\n );\n\n await execa(process.execPath, [TSX_CLI_PATH, extractFile, outputFile], {\n cwd: projectDir,\n stdio: \"pipe\",\n env: { ...process.env, NODE_ENV: \"production\" },\n });\n\n const outputResult = await readSourcePackageExtractorOutput(outputFile);\n if (!outputResult.success) return outputResult;\n\n const parsed = outputResult.value;\n if (parsed.length === 0) return success([]);\n\n return success(parsed);\n } catch (err) {\n const error = err as { stderr?: string; message?: string };\n return failure({\n code: \"CONFIG_LOAD_FAILED\",\n message: `Failed to load widget packages from ${config.relativePath}`,\n details: error.stderr ?? error.message ?? String(err),\n });\n } finally {\n if (tempDir) await fs.remove(tempDir).catch(() => {});\n }\n}\n\nasync function createTempDirectory(projectDir: string): Promise<string> {\n const projectTmpDir = path.join(projectDir, \".fluid\", \"tmp\");\n try {\n await fs.ensureDir(projectTmpDir);\n return await fs.mkdtemp(path.join(projectTmpDir, \"widget-packages-\"));\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(\n `Unable to create project-local temporary directory at ${projectTmpDir}: ${message}`,\n );\n }\n}\n\nasync function readSourcePackageExtractorOutput(\n outputFile: string,\n): Promise<Result<unknown[], WidgetSourceConfigLoadError>> {\n let output: string;\n try {\n output = await fs.readFile(outputFile, \"utf-8\");\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return failure({\n code: \"CONFIG_LOAD_FAILED\",\n message: \"Widget package extractor did not write an output file\",\n details: message,\n });\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(output);\n } catch {\n return failure({\n code: \"INVALID_FORMAT\",\n message: \"Failed to parse widget package output file as JSON\",\n details: `Output was: ${output.slice(0, 200)}`,\n });\n }\n\n if (!isRecord(parsed) || parsed.sentinel !== SOURCE_PACKAGE_OUTPUT_SENTINEL) {\n return failure({\n code: \"INVALID_FORMAT\",\n message: \"Widget package extractor output file had an invalid sentinel\",\n });\n }\n\n if (!Array.isArray(parsed.data)) {\n return failure({\n code: \"INVALID_FORMAT\",\n message: \"Extracted widget package output is not an array\",\n details: `Expected an array, got: ${typeof parsed.data}`,\n });\n }\n\n return success(parsed.data);\n}\n\nfunction createSourcePackageExtractorScript(options: {\n readonly projectDir: string;\n readonly configPath: string;\n}): string {\n return `\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { createServer, normalizePath } from \"vite\";\n\nconst SOURCE_PACKAGE_MARKER = \"__fluidSourceWidgetPackage\";\nconst OUTPUT_SENTINEL = ${JSON.stringify(SOURCE_PACKAGE_OUTPUT_SENTINEL)};\nconst projectRoot = ${JSON.stringify(options.projectDir)};\nconst widgetConfigPath = ${JSON.stringify(options.configPath)};\nconst outputPath = process.argv[2];\nif (!outputPath) throw new Error(\"Missing widget package extractor output path.\");\n\nfunction toViteModuleId(modulePath) {\n const relativePath = path.relative(projectRoot, modulePath);\n if (!relativePath.startsWith(\"..\") && !path.isAbsolute(relativePath)) {\n return \"/\" + normalizePath(relativePath);\n }\n return normalizePath(modulePath);\n}\n\nconst server = await createServer({\n root: projectRoot,\n mode: \"production\",\n server: { middlewareMode: true },\n appType: \"custom\",\n logLevel: \"error\",\n clearScreen: false,\n resolve: {\n conditions: [\"fluid-widget-authoring\"],\n },\n ssr: {\n noExternal: [\"@fluid-app/portal-sdk\"],\n resolve: {\n conditions: [\"fluid-widget-authoring\"],\n },\n },\n});\n\ntry {\n const widgetConfig = await server.ssrLoadModule(toViteModuleId(widgetConfigPath));\n\n function isSourceWidgetPackage(value) {\n return Boolean(value && typeof value === \"object\" && value[SOURCE_PACKAGE_MARKER] === true);\n }\n\n function collectSourceWidgetPackages(mod) {\n const candidates = [\n mod.widgetPackage,\n ...(Array.isArray(mod.widgetPackages) ? mod.widgetPackages : []),\n mod.default,\n ];\n const byPackageId = new Map();\n for (const candidate of candidates) {\n if (!isSourceWidgetPackage(candidate)) continue;\n if (!byPackageId.has(candidate.packageId)) byPackageId.set(candidate.packageId, candidate);\n }\n return Array.from(byPackageId.values());\n }\n\n function serializeWidget(widget) {\n if (!widget || typeof widget !== \"object\" || Array.isArray(widget)) {\n return widget;\n }\n const { component, ...metadata } = widget;\n return metadata;\n }\n\n function serializePackage(sourcePackage) {\n return {\n manifestVersion: sourcePackage.manifestVersion,\n scope: sourcePackage.scope,\n packageStableId: sourcePackage.packageStableId,\n packageId: sourcePackage.packageId,\n packageType: sourcePackage.packageType,\n version: sourcePackage.version,\n cssUrls: sourcePackage.cssUrls,\n widgets: Array.isArray(sourcePackage.widgets)\n ? sourcePackage.widgets.map(serializeWidget)\n : sourcePackage.widgets,\n };\n }\n\n await fs.writeFile(\n outputPath,\n JSON.stringify({\n sentinel: OUTPUT_SENTINEL,\n data: collectSourceWidgetPackages(widgetConfig).map(serializePackage),\n }),\n \"utf-8\",\n );\n} finally {\n await server.close();\n}\n`;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","/**\n * Manifest extraction utility\n *\n * Extracts serializable widget manifest metadata from portal.config.ts\n * by writing a minimal wrapper script that imports customWidgets plus\n * source widget package exports and serializes the result to a temp output\n * file, then running it with tsx.\n *\n * Strips the `component` field (not serializable) from each manifest.\n *\n * Writes a temp script, runs it with tsx, and parses JSON output from the\n * output file. The wrapper loads config modules through Vite SSR so project\n * aliases and Vite-compatible module resolution are honored.\n */\n\nimport { execa } from \"execa\";\nimport fs from \"fs-extra\";\nimport { createRequire } from \"node:module\";\nimport path from \"path\";\nimport { type Result, success, failure } from \"@fluid-app/fluid-cli\";\nimport { resolvePortalWidgetSourceConfig } from \"./widget-package-config.js\";\n\n/**\n * Serializable widget manifest — the JSON-safe subset of WidgetManifest.\n * Mirrors SerializableManifest from portal-core without the package dependency.\n */\nexport interface ExtractedManifest {\n readonly manifestVersion: number;\n readonly type: string;\n readonly displayName: string;\n readonly description: string;\n readonly icon: string;\n readonly category: string;\n readonly propertySchema: Record<string, unknown>;\n readonly defaultProps: Record<string, unknown>;\n readonly [key: string]: unknown;\n}\n\nexport interface ManifestExtractionError {\n readonly code: \"EXTRACTION_FAILED\" | \"INVALID_FORMAT\";\n readonly message: string;\n readonly details?: string;\n}\n\nconst EXTRACT_FILENAME = \"extract-manifests.ts\";\nconst EXTRACT_OUTPUT_FILENAME = \"manifests.json\";\nconst EXTRACT_OUTPUT_SENTINEL = \"fluid-widget-manifests:v1\";\nconst require = createRequire(import.meta.url);\nconst TSX_CLI_PATH = require.resolve(\"tsx/cli\");\n\n/**\n * Extract serializable widget manifests from a project's portal.config.ts.\n *\n * Writes a temp wrapper script, runs it with tsx, and parses the temp JSON\n * output file. The temp files are always cleaned up.\n *\n * Returns an empty array if no customWidgets or source package exports exist.\n *\n * Supported static export shapes are intentionally simple so the CLI can avoid\n * executing unrelated portal configs: named `export const|let|var customWidgets`,\n * `widgetPackage`, or `widgetPackages`; direct `export default\n * defineWidgetPackage(...)`; or `export default <identifier>` where that\n * identifier is initialized with `defineWidgetPackage(...)` in the same file.\n * Re-export-only and computed export shapes are not detected by this layer.\n *\n * @param projectDir - The project root directory containing src/portal.config.ts\n */\nexport async function extractManifests(\n projectDir: string,\n): Promise<Result<ExtractedManifest[], ManifestExtractionError>> {\n let tempDir: string | undefined;\n\n try {\n const config = await resolvePortalWidgetSourceConfig(projectDir);\n if (!config) {\n return success([]);\n }\n\n const configSource = await fs.readFile(config.path, \"utf-8\");\n const configExports = readStaticWidgetExports(configSource);\n const legacyPortalConfigPath = path.join(\n projectDir,\n \"src\",\n \"portal.config.ts\",\n );\n const shouldReadLegacyPortalConfig =\n path.resolve(config.path) !== path.resolve(legacyPortalConfigPath) &&\n (await fs.pathExists(legacyPortalConfigPath));\n const legacyPortalConfigExports = shouldReadLegacyPortalConfig\n ? readStaticWidgetExports(\n await fs.readFile(legacyPortalConfigPath, \"utf-8\"),\n )\n : undefined;\n const legacyCustomWidgetsConfigPath =\n legacyPortalConfigExports?.hasCustomWidgets\n ? legacyPortalConfigPath\n : undefined;\n\n if (\n !configExports.hasCustomWidgets &&\n !configExports.hasSourceWidgetPackages &&\n !legacyCustomWidgetsConfigPath\n ) {\n return success([]);\n }\n\n tempDir = await createTempDirectory(projectDir);\n const extractFile = path.join(tempDir, EXTRACT_FILENAME);\n const outputFile = path.join(tempDir, EXTRACT_OUTPUT_FILENAME);\n\n // Write wrapper script that imports manifests and strips component field\n const wrapperScript = createManifestExtractorScript({\n projectDir,\n widgetConfigPath: config.path,\n legacyCustomWidgetsConfigPath,\n });\n await fs.writeFile(extractFile, wrapperScript, {\n encoding: \"utf-8\",\n flag: \"wx\",\n });\n\n await execa(process.execPath, [TSX_CLI_PATH, extractFile, outputFile], {\n cwd: projectDir,\n stdio: \"pipe\",\n env: { ...process.env, NODE_ENV: \"production\" },\n });\n\n const outputResult = await readManifestExtractorOutput(outputFile);\n if (!outputResult.success) return outputResult;\n\n const parsed = outputResult.value;\n if (parsed.length === 0) {\n return success([]);\n }\n\n const validated = parsed.filter(\n (m): m is ExtractedManifest =>\n typeof m === \"object\" &&\n m !== null &&\n typeof (m as Record<string, unknown>).type === \"string\" &&\n typeof (m as Record<string, unknown>).displayName === \"string\",\n );\n return success(validated);\n } catch (err) {\n const error = err as { stderr?: string; message?: string };\n return failure({\n code: \"EXTRACTION_FAILED\",\n message:\n \"Failed to extract widget manifests from portal widget source config\",\n details: error.stderr ?? error.message ?? String(err),\n });\n } finally {\n if (tempDir) await fs.remove(tempDir).catch(() => {});\n }\n}\n\ninterface StaticWidgetExports {\n readonly hasCustomWidgets: boolean;\n readonly hasSourceWidgetPackages: boolean;\n}\n\nfunction readStaticWidgetExports(source: string): StaticWidgetExports {\n // Strip comments so the regex doesn't match commented-out exports\n const strippedSource = source\n .replace(/\\/\\/[^\\n]*/g, \"\")\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\");\n\n const defaultExportMatch = /export\\s+default\\s+([A-Za-z_$][\\w$]*)\\b/.exec(\n strippedSource,\n );\n const widgetPackageDefinitionNames = new Set(\n Array.from(\n strippedSource.matchAll(\n /\\b(?:const|let|var)\\s+([A-Za-z_$][\\w$]*)(?:\\s*:[^=]+)?\\s*=\\s*defineWidgetPackage\\s*\\(/g,\n ),\n (match) => match[1],\n ),\n );\n const hasDefaultWidgetPackageExport =\n /export\\s+default\\s+defineWidgetPackage\\s*\\(/.test(strippedSource) ||\n (defaultExportMatch !== null &&\n widgetPackageDefinitionNames.has(defaultExportMatch[1]));\n\n return {\n hasCustomWidgets: /export\\s+(?:const|let|var)\\s+customWidgets\\b/.test(\n strippedSource,\n ),\n hasSourceWidgetPackages:\n /export\\s+(?:const|let|var)\\s+widgetPackage\\b/.test(strippedSource) ||\n /export\\s+(?:const|let|var)\\s+widgetPackages\\b/.test(strippedSource) ||\n hasDefaultWidgetPackageExport,\n };\n}\n\nasync function createTempDirectory(projectDir: string): Promise<string> {\n const projectTmpDir = path.join(projectDir, \".fluid\", \"tmp\");\n try {\n await fs.ensureDir(projectTmpDir);\n return await fs.mkdtemp(path.join(projectTmpDir, \"manifests-\"));\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(\n `Unable to create project-local temporary directory at ${projectTmpDir}: ${message}`,\n );\n }\n}\n\nasync function readManifestExtractorOutput(\n outputFile: string,\n): Promise<Result<unknown[], ManifestExtractionError>> {\n let output: string;\n try {\n output = await fs.readFile(outputFile, \"utf-8\");\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return failure({\n code: \"EXTRACTION_FAILED\",\n message: \"Manifest extractor did not write an output file\",\n details: message,\n });\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(output);\n } catch {\n return failure({\n code: \"INVALID_FORMAT\",\n message: \"Failed to parse manifest output file as JSON\",\n details: `Output was: ${output.slice(0, 200)}`,\n });\n }\n\n if (!isRecord(parsed) || parsed.sentinel !== EXTRACT_OUTPUT_SENTINEL) {\n return failure({\n code: \"INVALID_FORMAT\",\n message: \"Manifest extractor output file had an invalid sentinel\",\n });\n }\n\n if (!Array.isArray(parsed.data)) {\n return failure({\n code: \"INVALID_FORMAT\",\n message: \"extracted widget manifests output is not an array\",\n details: `Expected an array, got: ${typeof parsed.data}`,\n });\n }\n\n return success(parsed.data);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction createManifestExtractorScript(options: {\n readonly projectDir: string;\n readonly widgetConfigPath: string;\n readonly legacyCustomWidgetsConfigPath?: string;\n}): string {\n return `\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { createServer, normalizePath } from \"vite\";\nimport {\n isSourceWidgetPackage,\n sourceWidgetPackagesToManifests,\n} from \"@fluid-app/portal-sdk\";\n\nconst OUTPUT_SENTINEL = ${JSON.stringify(EXTRACT_OUTPUT_SENTINEL)};\nconst projectRoot = ${JSON.stringify(options.projectDir)};\nconst widgetConfigPath = ${JSON.stringify(options.widgetConfigPath)};\nconst legacyCustomWidgetsConfigPath = ${JSON.stringify(options.legacyCustomWidgetsConfigPath)};\nconst outputPath = process.argv[2];\nif (!outputPath) throw new Error(\"Missing manifest extractor output path.\");\n\nfunction toViteModuleId(modulePath) {\n const relativePath = path.relative(projectRoot, modulePath);\n if (!relativePath.startsWith(\"..\") && !path.isAbsolute(relativePath)) {\n return \"/\" + normalizePath(relativePath);\n }\n return normalizePath(modulePath);\n}\n\nconst server = await createServer({\n root: projectRoot,\n mode: \"production\",\n server: { middlewareMode: true },\n appType: \"custom\",\n logLevel: \"error\",\n clearScreen: false,\n});\n\ntry {\n const portalConfig = await server.ssrLoadModule(toViteModuleId(widgetConfigPath));\n const legacyPortalConfig = legacyCustomWidgetsConfigPath\n ? await server.ssrLoadModule(toViteModuleId(legacyCustomWidgetsConfigPath))\n : {};\n\n const sourcePackages = [];\n const seenSourcePackageIds = new Set();\n for (const candidate of [\n portalConfig.widgetPackage,\n ...(Array.isArray(portalConfig.widgetPackages) ? portalConfig.widgetPackages : []),\n portalConfig.default,\n ]) {\n if (!isSourceWidgetPackage(candidate)) continue;\n if (seenSourcePackageIds.has(candidate.packageId)) continue;\n seenSourcePackageIds.add(candidate.packageId);\n sourcePackages.push(candidate);\n }\n const manifests = [\n ...(Array.isArray(portalConfig.customWidgets) ? portalConfig.customWidgets : []),\n ...(Array.isArray(legacyPortalConfig.customWidgets) ? legacyPortalConfig.customWidgets : []),\n ...sourceWidgetPackagesToManifests(sourcePackages),\n ];\n const serializable = manifests.map(({ component, ...rest }) => rest);\n await fs.writeFile(\n outputPath,\n JSON.stringify({ sentinel: OUTPUT_SENTINEL, data: serializable }),\n \"utf-8\",\n );\n} finally {\n await server.close();\n}\n`;\n}\n","import { Command } from \"commander\";\nimport type { PluginContext } from \"@fluid-app/fluid-cli\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { execa } from \"execa\";\nimport { existsSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { BuildOptions } from \"../types.js\";\nimport { extractManifests } from \"../utils/extract-manifests.js\";\n\nexport const buildCommand: Command = new Command(\"build\")\n .description(\"Build the application for production\")\n .option(\"-o, --out-dir <dir>\", \"Output directory\", \"dist\")\n .action(async (options: BuildOptions) => {\n const cwd = process.cwd();\n\n // Check if we're in a Fluid project\n const packageJsonPath = join(cwd, \"package.json\");\n if (!existsSync(packageJsonPath)) {\n console.error(\n chalk.red(\"Error: No package.json found in current directory\"),\n );\n console.error(\n chalk.yellow(\"Make sure you're in a Fluid project directory\"),\n );\n process.exit(1);\n }\n\n // Check for vite.config\n const viteConfigPath = join(cwd, \"vite.config.ts\");\n if (!existsSync(viteConfigPath)) {\n console.error(chalk.red(\"Error: No vite.config.ts found\"));\n console.error(\n chalk.yellow(\"This command must be run from a Fluid project directory\"),\n );\n process.exit(1);\n }\n\n console.log();\n console.log(chalk.bold(\"Building for production...\"));\n console.log();\n\n const spinner = ora(\"Building...\").start();\n\n try {\n // Run the project's build script\n await execa(\"pnpm\", [\"run\", \"build\"], {\n cwd,\n stdio: \"pipe\",\n });\n\n spinner.succeed(\"Build completed\");\n\n // Extract widget manifests and write to build output.\n // The manifest plugin emits an empty __manifests__.json to the Vite outDir.\n // We overwrite it with real data. Check both common outDir layouts:\n // - \"dist/public\" (monorepo portal)\n // - \"dist\" (starter template, Vite default)\n const manifestSpinner = ora(\"Extracting widget manifests...\").start();\n const outDir = options.outDir ?? \"dist\";\n const manifestResult = await extractManifests(cwd);\n\n // Find where the empty __manifests__.json was emitted by the manifest plugin\n const candidatePaths = [\n join(cwd, outDir, \"__manifests__.json\"),\n join(cwd, outDir, \"public\", \"__manifests__.json\"),\n ];\n const manifestPath = candidatePaths.find((p) => existsSync(p));\n\n if (manifestResult.success) {\n if (manifestResult.value.length === 0) {\n manifestSpinner.info(\"No custom widgets found\");\n } else if (!manifestPath) {\n manifestSpinner.warn(\n `__manifests__.json not found in build output — skipping manifest write`,\n );\n } else {\n writeFileSync(manifestPath, JSON.stringify(manifestResult.value));\n manifestSpinner.succeed(\n `Extracted ${manifestResult.value.length} widget manifest(s)`,\n );\n }\n } else {\n manifestSpinner.warn(\n `Manifest extraction failed: ${manifestResult.error.message}`,\n );\n }\n\n console.log();\n console.log(`Output written to ${chalk.cyan(outDir)}/`);\n console.log();\n console.log(\"To preview the build locally:\");\n console.log(chalk.cyan(\" pnpm vite preview\"));\n console.log();\n } catch (error) {\n spinner.fail(\"Build failed\");\n const execaError = error as { stderr?: string };\n if (execaError.stderr) {\n console.error(execaError.stderr);\n }\n process.exit(1);\n }\n });\n\nexport function registerBuildCommand(ctx: PluginContext): void {\n ctx.program.addCommand(buildCommand);\n}\n","/**\n * Cross-reference validation and change categorization utilities for the push command.\n *\n * Extracted into a standalone utility so that pure logic can be tested\n * without pulling in CLI dependencies (ora, chalk, prompts, etc.).\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { join, basename } from \"node:path\";\nimport { existsSync, readdirSync } from \"node:fs\";\n\nimport type { PortalMappings } from \"./mappings.js\";\nimport type { SnapshotDiff } from \"./snapshot.js\";\nimport type {\n LocalNavigation,\n LocalNavigationItem,\n LocalProfile,\n} from \"./transform.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Categorize changed files by resource type. */\nexport interface CategorizedChanges {\n readonly screens: { new: string[]; changed: string[]; deleted: string[] };\n readonly themes: { new: string[]; changed: string[]; deleted: string[] };\n readonly navigations: { new: string[]; changed: string[]; deleted: string[] };\n readonly profiles: { new: string[]; changed: string[]; deleted: string[] };\n}\n\n/** A validation error found during cross-reference checking. */\nexport interface ValidationError {\n readonly file: string;\n readonly message: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Extract the slug from a file path (e.g., \"screens/home.json\" -> \"home\").\n */\nexport function slugFromPath(filePath: string): string {\n return basename(filePath, \".json\");\n}\n\n/**\n * Extract the resource type directory from a file path (e.g., \"screens/home.json\" -> \"screens\").\n */\nfunction resourceTypeFromPath(\n filePath: string,\n): \"screens\" | \"themes\" | \"navigations\" | \"profiles\" | null {\n const dir = filePath.split(\"/\")[0];\n if (\n dir === \"screens\" ||\n dir === \"themes\" ||\n dir === \"navigations\" ||\n dir === \"profiles\"\n ) {\n return dir;\n }\n return null;\n}\n\n/**\n * Read and parse a JSON file from the portal directory.\n */\nasync function readPortalFile<T>(\n portalDir: string,\n relativePath: string,\n): Promise<T> {\n const filePath = join(portalDir, relativePath);\n const content = await readFile(filePath, \"utf-8\");\n return JSON.parse(content) as T;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Change categorization\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Categorize a snapshot diff into resource-type-specific change lists.\n */\nexport function categorizeChanges(diff: SnapshotDiff): CategorizedChanges {\n const result: CategorizedChanges = {\n screens: { new: [], changed: [], deleted: [] },\n themes: { new: [], changed: [], deleted: [] },\n navigations: { new: [], changed: [], deleted: [] },\n profiles: { new: [], changed: [], deleted: [] },\n };\n\n for (const file of diff.new) {\n const type = resourceTypeFromPath(file);\n if (type) result[type].new.push(file);\n }\n for (const file of diff.changed) {\n const type = resourceTypeFromPath(file);\n if (type) result[type].changed.push(file);\n }\n for (const file of diff.deleted) {\n const type = resourceTypeFromPath(file);\n if (type) result[type].deleted.push(file);\n }\n\n return result;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Cross-reference validation\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Validate that all cross-references between local portal files are valid.\n *\n * Checks:\n * - Navigation items' \"screen\" slugs reference existing screen files or mappings\n * - Profile \"navigation\" and \"mobile_navigation\" slugs reference existing nav files or mappings\n * - Profile \"themes\" slugs reference existing theme files or mappings\n */\nexport async function validateCrossReferences(\n portalDir: string,\n mappings: PortalMappings,\n changes: CategorizedChanges,\n): Promise<ValidationError[]> {\n const errors: ValidationError[] = [];\n\n // Build sets of valid slugs (existing mappings + local files on disk)\n const validScreenSlugs = buildValidSlugsSet(portalDir, \"screens\", mappings);\n const validNavSlugs = buildValidSlugsSet(portalDir, \"navigations\", mappings);\n const validThemeSlugs = buildValidSlugsSet(portalDir, \"themes\", mappings);\n\n // Remove deleted resource slugs from valid sets\n for (const file of changes.screens.deleted) {\n validScreenSlugs.delete(slugFromPath(file));\n }\n for (const file of changes.navigations.deleted) {\n validNavSlugs.delete(slugFromPath(file));\n }\n for (const file of changes.themes.deleted) {\n validThemeSlugs.delete(slugFromPath(file));\n }\n\n // Validate navigation files (new + changed)\n const navFilesToCheck = [\n ...changes.navigations.new,\n ...changes.navigations.changed,\n ];\n for (const file of navFilesToCheck) {\n try {\n const nav = await readPortalFile<LocalNavigation>(portalDir, file);\n validateNavigationItems(\n nav.navigation_items,\n file,\n validScreenSlugs,\n errors,\n );\n } catch {\n errors.push({ file, message: \"Failed to read navigation file\" });\n }\n }\n\n // Validate profile files (new + changed)\n const profileFilesToCheck = [\n ...changes.profiles.new,\n ...changes.profiles.changed,\n ];\n for (const file of profileFilesToCheck) {\n try {\n const profile = await readPortalFile<LocalProfile>(portalDir, file);\n\n if (profile.navigation && !validNavSlugs.has(profile.navigation)) {\n errors.push({\n file,\n message: `References navigation \"${profile.navigation}\" which does not exist`,\n });\n }\n\n if (\n profile.mobile_navigation &&\n !validNavSlugs.has(profile.mobile_navigation)\n ) {\n errors.push({\n file,\n message: `References mobile_navigation \"${profile.mobile_navigation}\" which does not exist`,\n });\n }\n\n for (const themeSlug of profile.themes) {\n if (!validThemeSlugs.has(themeSlug)) {\n errors.push({\n file,\n message: `References theme \"${themeSlug}\" which does not exist`,\n });\n }\n }\n } catch {\n errors.push({ file, message: \"Failed to read profile file\" });\n }\n }\n\n return errors;\n}\n\n/**\n * Build a set of valid slugs for a resource type by combining\n * existing mapping slugs with local file slugs on disk.\n */\nfunction buildValidSlugsSet(\n portalDir: string,\n resourceType: \"screens\" | \"themes\" | \"navigations\" | \"profiles\",\n mappings: PortalMappings,\n): Set<string> {\n const slugs = new Set<string>();\n\n // Add all slugs from mappings\n for (const slug of Object.keys(mappings[resourceType])) {\n slugs.add(slug);\n }\n\n // Add slugs from local files on disk\n const dir = join(portalDir, resourceType);\n if (existsSync(dir)) {\n try {\n const entries = readdirSync(dir);\n for (const entry of entries) {\n if (entry.endsWith(\".json\")) {\n slugs.add(basename(entry, \".json\"));\n }\n }\n } catch {\n // Directory doesn't exist or can't be read — skip\n }\n }\n\n return slugs;\n}\n\n/**\n * Recursively validate navigation item screen references.\n */\nfunction validateNavigationItems(\n items: LocalNavigationItem[],\n file: string,\n validScreenSlugs: Set<string>,\n errors: ValidationError[],\n): void {\n for (const item of items) {\n if (item.screen && !validScreenSlugs.has(item.screen)) {\n errors.push({\n file,\n message: `Navigation item \"${item.label ?? \"(unlabeled)\"}\" references screen \"${item.screen}\" which does not exist`,\n });\n }\n if (item.children && item.children.length > 0) {\n validateNavigationItems(item.children, file, validScreenSlugs, errors);\n }\n }\n}\n","/**\n * `fluid portal push` command\n *\n * Pushes local portal content changes to the Fluid OS API.\n * Detects changes since the last pull/push via snapshot diffing,\n * validates cross-references, and pushes resources in dependency order.\n */\n\nimport { Command } from \"commander\";\nimport type { PluginContext } from \"@fluid-app/fluid-cli\";\nimport { getAuthToken, getActiveProfile } from \"@fluid-app/fluid-cli\";\nimport { createFetchClient } from \"@fluid-app/fluidos-api-client\";\nimport type { FetchClient, components } from \"@fluid-app/fluidos-api-client\";\nimport { fluidOs } from \"@fluid-app/fluidos-api-client\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { join } from \"node:path\";\nimport { readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport prompts from \"prompts\";\n\nimport {\n readMappings,\n writeMappings,\n updateMapping,\n removeMapping,\n resolveSlugToId,\n} from \"../utils/mappings.js\";\nimport type { PortalMappings } from \"../utils/mappings.js\";\nimport {\n readSnapshot,\n diffAgainstSnapshot,\n writeSnapshot,\n computeFileHash,\n} from \"../utils/snapshot.js\";\nimport type { SnapshotDiff } from \"../utils/snapshot.js\";\nimport type {\n LocalScreen,\n LocalTheme,\n LocalNavigation,\n LocalNavigationItem,\n LocalProfile,\n} from \"../utils/transform.js\";\nimport {\n categorizeChanges,\n validateCrossReferences,\n slugFromPath,\n} from \"../utils/push-validation.js\";\nimport type { CategorizedChanges } from \"../utils/push-validation.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Derived from the generated FluidOSNavigationItem but with `id` optional\n * (new items don't have one yet) and `label`/`position` required (needed\n * for create/update payloads).\n */\ntype NavigationSyncItem = Omit<\n components[\"schemas\"][\"FluidOSNavigationItem\"],\n \"id\" | \"label\" | \"position\" | \"children\"\n> & {\n id?: number;\n label: string;\n position: number;\n children?: NavigationSyncItem[];\n parent_id?: number | null;\n};\n\ninterface PushOptions {\n yes?: boolean;\n}\n\n/** Result of a single push operation. */\ninterface PushResult {\n readonly file: string;\n readonly action: \"created\" | \"updated\" | \"deleted\";\n readonly success: boolean;\n readonly error?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Constants\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst PORTAL_DIR = \"portal\";\nconst PORTAL_SYNC_DIR = \".portal-sync\";\n\n/**\n * Convert the local array-form component_tree back to the object\n * the API expects. The pull command normalizes the API object into\n * an array for local convenience; this reverses that transformation.\n */\nfunction toApiComponentTree(\n tree: Record<string, unknown>[],\n): Record<string, unknown> | null {\n if (tree.length === 0) return null;\n if (tree.length === 1) return tree[0]!;\n // Fallback: wrap multiple roots in a container (shouldn't happen in practice)\n return { children: tree };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Create an authenticated FetchClient using the stored CLI profile.\n */\nfunction createClient(): FetchClient {\n const token = getAuthToken();\n if (!token) {\n const profile = getActiveProfile();\n if (!profile) {\n throw new Error(\n \"Not logged in. Run \" + chalk.cyan(\"fluid login\") + \" first.\",\n );\n }\n throw new Error(\n \"No auth token found for profile \" +\n chalk.cyan(profile.name) +\n \". Run \" +\n chalk.cyan(\"fluid login\") +\n \" to re-authenticate.\",\n );\n }\n\n const baseUrl = process.env[\"FLUID_API_BASE\"] ?? \"https://api.fluid.app\";\n\n return createFetchClient({\n baseUrl,\n getAuthToken: () => token,\n });\n}\n\n/**\n * Extract an enriched error message from a caught value.\n * Includes structured API error data when available.\n */\nfunction enrichedErrorMessage(err: unknown): string {\n let msg = err instanceof Error ? err.message : String(err);\n if (err && typeof err === \"object\" && \"data\" in err) {\n msg += ` — ${JSON.stringify((err as { data: unknown }).data)}`;\n }\n return msg;\n}\n\n/**\n * Read and parse a JSON file from the portal directory.\n */\nasync function readPortalFile<T>(\n portalDir: string,\n relativePath: string,\n): Promise<T> {\n const filePath = join(portalDir, relativePath);\n const content = await readFile(filePath, \"utf-8\");\n return JSON.parse(content) as T;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Resource push functions\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Push screen changes to the API.\n */\nasync function pushScreens(\n client: FetchClient,\n defId: number,\n portalDir: string,\n changes: CategorizedChanges[\"screens\"],\n mappings: PortalMappings,\n): Promise<{ results: PushResult[]; mappings: PortalMappings }> {\n const results: PushResult[] = [];\n let currentMappings = mappings;\n\n // Create new screens\n for (const file of changes.new) {\n const slug = slugFromPath(file);\n try {\n const local = await readPortalFile<LocalScreen>(portalDir, file);\n const response = await fluidOs.fluid_os_v0_create_fluid_osscreen(\n client,\n defId,\n {\n screen: {\n name: local.name,\n slug,\n component_tree: toApiComponentTree(\n local.component_tree,\n ) as unknown as Record<string, unknown>,\n },\n },\n );\n const newId = response.screen?.id;\n if (newId != null) {\n currentMappings = updateMapping(\n currentMappings,\n \"screens\",\n slug,\n newId,\n );\n }\n results.push({ file, action: \"created\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"created\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n // Update changed screens\n for (const file of changes.changed) {\n const slug = slugFromPath(file);\n const screenId = resolveSlugToId(currentMappings, \"screens\", slug);\n if (screenId == null) {\n results.push({\n file,\n action: \"updated\",\n success: false,\n error: `No mapping found for screen slug \"${slug}\"`,\n });\n return { results, mappings: currentMappings };\n }\n try {\n const local = await readPortalFile<LocalScreen>(portalDir, file);\n await fluidOs.fluid_os_v0_update_fluid_osscreen(client, defId, screenId, {\n screen: {\n name: local.name,\n slug,\n component_tree: toApiComponentTree(\n local.component_tree,\n ) as unknown as Record<string, unknown>,\n },\n });\n results.push({ file, action: \"updated\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"updated\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n // Delete screens\n for (const file of changes.deleted) {\n const slug = slugFromPath(file);\n const screenId = resolveSlugToId(currentMappings, \"screens\", slug);\n if (screenId == null) {\n results.push({\n file,\n action: \"deleted\",\n success: false,\n error: `No mapping found for screen slug \"${slug}\"`,\n });\n return { results, mappings: currentMappings };\n }\n try {\n await fluidOs.fluid_os_v0_delete_fluid_osscreen(client, defId, screenId);\n currentMappings = removeMapping(currentMappings, \"screens\", slug);\n results.push({ file, action: \"deleted\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"deleted\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n return { results, mappings: currentMappings };\n}\n\n/**\n * Push theme changes to the API.\n */\nasync function pushThemes(\n client: FetchClient,\n defId: number,\n portalDir: string,\n changes: CategorizedChanges[\"themes\"],\n mappings: PortalMappings,\n): Promise<{ results: PushResult[]; mappings: PortalMappings }> {\n const results: PushResult[] = [];\n let currentMappings = mappings;\n\n // Create new themes\n for (const file of changes.new) {\n const slug = slugFromPath(file);\n try {\n const local = await readPortalFile<LocalTheme>(portalDir, file);\n const response = await fluidOs.fluid_os_v0_create_fluid_ostheme(\n client,\n defId,\n {\n theme: {\n name: local.name,\n active: local.active,\n config: local.config,\n },\n },\n );\n const newId = response.theme?.id;\n if (newId != null) {\n currentMappings = updateMapping(currentMappings, \"themes\", slug, newId);\n }\n results.push({ file, action: \"created\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"created\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n // Update changed themes\n for (const file of changes.changed) {\n const slug = slugFromPath(file);\n const themeId = resolveSlugToId(currentMappings, \"themes\", slug);\n if (themeId == null) {\n results.push({\n file,\n action: \"updated\",\n success: false,\n error: `No mapping found for theme slug \"${slug}\"`,\n });\n return { results, mappings: currentMappings };\n }\n try {\n const local = await readPortalFile<LocalTheme>(portalDir, file);\n await fluidOs.fluid_os_v0_update_fluid_ostheme(client, defId, themeId, {\n theme: {\n name: local.name,\n active: local.active,\n config: local.config,\n },\n });\n results.push({ file, action: \"updated\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"updated\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n // Delete themes\n for (const file of changes.deleted) {\n const slug = slugFromPath(file);\n const themeId = resolveSlugToId(currentMappings, \"themes\", slug);\n if (themeId == null) {\n results.push({\n file,\n action: \"deleted\",\n success: false,\n error: `No mapping found for theme slug \"${slug}\"`,\n });\n return { results, mappings: currentMappings };\n }\n try {\n await fluidOs.fluid_os_v0_delete_fluid_ostheme(client, defId, themeId);\n currentMappings = removeMapping(currentMappings, \"themes\", slug);\n results.push({ file, action: \"deleted\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"deleted\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n return { results, mappings: currentMappings };\n}\n\n/**\n * Resolve screen slug references to screen IDs in navigation items.\n * Returns a new tree with `screen_id` instead of `screen` slug,\n * shaped to match the FluidOSNavigationItemSyncItem schema.\n */\nfunction resolveNavigationItemScreenIds(\n items: LocalNavigationItem[],\n mappings: PortalMappings,\n): NavigationSyncItem[] {\n return items.map((item) => {\n const screenId = item.screen\n ? (resolveSlugToId(mappings, \"screens\", item.screen) ?? undefined)\n : undefined;\n const result: NavigationSyncItem = {\n ...(item.id ? { id: item.id } : {}),\n label: item.label ?? \"\",\n position: item.position ?? 0,\n icon: item.icon,\n screen_id: screenId ?? null,\n slug: item.slug,\n source: (item.source as \"user\" | \"system\" | \"code\") ?? \"user\",\n parent_id: item.parent_id,\n children: resolveNavigationItemScreenIds(item.children ?? [], mappings),\n };\n return result;\n });\n}\n\n/**\n * Flatten a tree of navigation sync items into a flat list.\n * The API reconciliation logic requires a flat list to correctly\n * compare against the flat server response.\n */\nfunction flattenNavigationItems(\n items: NavigationSyncItem[],\n): NavigationSyncItem[] {\n const flat: NavigationSyncItem[] = [];\n for (const item of items) {\n const { children, ...rest } = item;\n flat.push(rest as NavigationSyncItem);\n if (children && children.length > 0) {\n flat.push(...flattenNavigationItems(children as NavigationSyncItem[]));\n }\n }\n return flat;\n}\n\n/**\n * Push navigation changes to the API.\n */\nasync function pushNavigations(\n client: FetchClient,\n defId: number,\n portalDir: string,\n changes: CategorizedChanges[\"navigations\"],\n mappings: PortalMappings,\n): Promise<{ results: PushResult[]; mappings: PortalMappings }> {\n const results: PushResult[] = [];\n let currentMappings = mappings;\n\n // Create new navigations\n for (const file of changes.new) {\n const slug = slugFromPath(file);\n try {\n const local = await readPortalFile<LocalNavigation>(portalDir, file);\n const response = await fluidOs.fluid_os_v0_create_fluid_osnavigation(\n client,\n defId,\n {\n navigation: {\n name: local.name,\n platform: local.platform as \"web\" | \"mobile\",\n },\n },\n );\n const newId = response.navigation?.id;\n if (newId != null) {\n currentMappings = updateMapping(\n currentMappings,\n \"navigations\",\n slug,\n newId,\n );\n // Create navigation items individually (flatten tree for API).\n // Track local→server ID mapping so child items reference the\n // correct server-assigned parent IDs.\n const resolvedItems = flattenNavigationItems(\n resolveNavigationItemScreenIds(\n local.navigation_items,\n currentMappings,\n ),\n );\n const localToServerId = new Map<number, number>();\n\n for (const item of resolvedItems) {\n const resolvedParentId =\n item.parent_id != null\n ? (localToServerId.get(item.parent_id) ?? item.parent_id)\n : undefined;\n\n const created =\n await fluidOs.fluid_os_v0_create_fluid_osnavigation_item(\n client,\n defId,\n newId,\n {\n navigation_item: {\n label: item.label ?? \"\",\n position: item.position ?? 0,\n icon: item.icon ?? undefined,\n screen_id: item.screen_id ?? undefined,\n slug: item.slug ?? undefined,\n source: item.source ?? undefined,\n parent_id: resolvedParentId,\n },\n },\n );\n\n if (item.id != null && created.navigation_item?.id != null) {\n localToServerId.set(item.id, created.navigation_item.id);\n }\n }\n }\n results.push({ file, action: \"created\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"created\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n // Update changed navigations\n for (const file of changes.changed) {\n const slug = slugFromPath(file);\n const navId = resolveSlugToId(currentMappings, \"navigations\", slug);\n if (navId == null) {\n results.push({\n file,\n action: \"updated\",\n success: false,\n error: `No mapping found for navigation slug \"${slug}\"`,\n });\n return { results, mappings: currentMappings };\n }\n try {\n const local = await readPortalFile<LocalNavigation>(portalDir, file);\n\n // Update navigation metadata\n await fluidOs.fluid_os_v0_update_fluid_osnavigation(\n client,\n defId,\n navId,\n {\n navigation: {\n name: local.name,\n platform: local.platform as \"web\" | \"mobile\",\n },\n },\n );\n\n // Reconcile navigation items via individual CRUD operations.\n // The bulk sync endpoint is unreliable, so we diff local vs server\n // and issue create/update/delete calls like the admin builder does.\n // Flatten the tree since the API returns/expects a flat list.\n const resolvedItems = flattenNavigationItems(\n resolveNavigationItemScreenIds(local.navigation_items, currentMappings),\n );\n\n const serverResponse =\n await fluidOs.fluid_os_v0_list_fluid_osnavigation_items(\n client,\n defId,\n navId,\n );\n const serverItems = serverResponse.navigation_items ?? [];\n const serverById = new Map(serverItems.map((s) => [s.id, s]));\n const localIds = new Set(\n resolvedItems.filter((i) => i.id).map((i) => i.id),\n );\n\n // Delete server items not in local\n for (const serverItem of serverItems) {\n if (!localIds.has(serverItem.id)) {\n await fluidOs.fluid_os_v0_delete_fluid_osnavigation_item(\n client,\n defId,\n navId,\n serverItem.id,\n );\n }\n }\n\n // Create or update local items.\n // Track local→server ID mapping so newly created child items\n // reference the correct server-assigned parent IDs.\n const localToServerId = new Map<number, number>();\n\n for (const item of resolvedItems) {\n const resolvedParentId =\n item.parent_id != null\n ? (localToServerId.get(item.parent_id) ?? item.parent_id)\n : undefined;\n\n const body = {\n label: item.label,\n position: item.position,\n icon: item.icon ?? undefined,\n screen_id: item.screen_id ?? undefined,\n slug: item.slug ?? undefined,\n source: item.source ?? undefined,\n parent_id: resolvedParentId,\n };\n\n if (item.id && serverById.has(item.id)) {\n // Update existing\n await fluidOs.fluid_os_v0_update_fluid_osnavigation_item(\n client,\n defId,\n navId,\n item.id,\n { navigation_item: body },\n );\n } else {\n // Create new\n const created =\n await fluidOs.fluid_os_v0_create_fluid_osnavigation_item(\n client,\n defId,\n navId,\n {\n navigation_item: {\n ...body,\n label: body.label ?? \"\",\n position: body.position ?? 0,\n },\n },\n );\n\n if (item.id != null && created.navigation_item?.id != null) {\n localToServerId.set(item.id, created.navigation_item.id);\n }\n }\n }\n\n results.push({ file, action: \"updated\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"updated\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n // Delete navigations\n for (const file of changes.deleted) {\n const slug = slugFromPath(file);\n const navId = resolveSlugToId(currentMappings, \"navigations\", slug);\n if (navId == null) {\n results.push({\n file,\n action: \"deleted\",\n success: false,\n error: `No mapping found for navigation slug \"${slug}\"`,\n });\n return { results, mappings: currentMappings };\n }\n try {\n await fluidOs.fluid_os_v0_delete_fluid_osnavigation(client, defId, navId);\n currentMappings = removeMapping(currentMappings, \"navigations\", slug);\n results.push({ file, action: \"deleted\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"deleted\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n return { results, mappings: currentMappings };\n}\n\n/**\n * Push profile changes to the API.\n */\nasync function pushProfiles(\n client: FetchClient,\n defId: number,\n portalDir: string,\n changes: CategorizedChanges[\"profiles\"],\n mappings: PortalMappings,\n): Promise<{ results: PushResult[]; mappings: PortalMappings }> {\n const results: PushResult[] = [];\n let currentMappings = mappings;\n\n // Create new profiles\n for (const file of changes.new) {\n const slug = slugFromPath(file);\n try {\n const local = await readPortalFile<LocalProfile>(portalDir, file);\n const body = resolveProfileBody(local, currentMappings);\n const response = await fluidOs.fluid_os_v0_create_fluid_osprofile(\n client,\n defId,\n {\n profile: body,\n },\n );\n const newId = response.profile?.id;\n if (newId != null) {\n currentMappings = updateMapping(\n currentMappings,\n \"profiles\",\n slug,\n newId,\n );\n }\n results.push({ file, action: \"created\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"created\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n // Update changed profiles\n for (const file of changes.changed) {\n const slug = slugFromPath(file);\n const profileId = resolveSlugToId(currentMappings, \"profiles\", slug);\n if (profileId == null) {\n results.push({\n file,\n action: \"updated\",\n success: false,\n error: `No mapping found for profile slug \"${slug}\"`,\n });\n return { results, mappings: currentMappings };\n }\n try {\n const local = await readPortalFile<LocalProfile>(portalDir, file);\n const body = resolveProfileBody(local, currentMappings);\n await fluidOs.fluid_os_v0_update_fluid_osprofile(\n client,\n defId,\n profileId,\n {\n profile: body,\n },\n );\n results.push({ file, action: \"updated\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"updated\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n // Delete profiles\n for (const file of changes.deleted) {\n const slug = slugFromPath(file);\n const profileId = resolveSlugToId(currentMappings, \"profiles\", slug);\n if (profileId == null) {\n results.push({\n file,\n action: \"deleted\",\n success: false,\n error: `No mapping found for profile slug \"${slug}\"`,\n });\n return { results, mappings: currentMappings };\n }\n try {\n await fluidOs.fluid_os_v0_delete_fluid_osprofile(\n client,\n defId,\n profileId,\n );\n currentMappings = removeMapping(currentMappings, \"profiles\", slug);\n results.push({ file, action: \"deleted\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"deleted\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n return { results, mappings: currentMappings };\n}\n\n/** Typed profile body for API requests (create and update share the same shape). */\ninterface ProfileBody {\n name: string;\n default?: boolean;\n navigation_id?: number;\n mobile_navigation_id?: number;\n theme_ids?: number[];\n permissions?: {\n countries?: number[];\n ranks?: number[];\n roles?: string[];\n platform?: string[];\n };\n}\n\n/**\n * Resolve profile slug references to API IDs for create/update request body.\n */\nfunction resolveProfileBody(\n local: LocalProfile,\n mappings: PortalMappings,\n): ProfileBody {\n const body: ProfileBody = {\n name: local.name,\n default: local.default,\n permissions: local.permissions,\n };\n\n if (local.navigation) {\n const navId = resolveSlugToId(mappings, \"navigations\", local.navigation);\n if (navId != null) {\n body.navigation_id = navId;\n }\n }\n\n if (local.mobile_navigation) {\n const mobileNavId = resolveSlugToId(\n mappings,\n \"navigations\",\n local.mobile_navigation,\n );\n if (mobileNavId != null) {\n body.mobile_navigation_id = mobileNavId;\n }\n }\n\n const themeIds = local.themes\n .map((slug) => resolveSlugToId(mappings, \"themes\", slug))\n .filter((id): id is number => id != null);\n body.theme_ids = themeIds;\n\n return body;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Print helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction printChangesSummary(diff: SnapshotDiff, definitionName: string): void {\n console.log(\n chalk.blue(\"Changes to push for \") +\n chalk.white.bold(`\"${definitionName}\"`) +\n chalk.blue(\":\"),\n );\n console.log();\n\n if (diff.new.length > 0) {\n console.log(chalk.green(\" New: \") + diff.new.join(\", \"));\n }\n if (diff.changed.length > 0) {\n console.log(chalk.yellow(\" Changed: \") + diff.changed.join(\", \"));\n }\n if (diff.deleted.length > 0) {\n console.log(chalk.red(\" Deleted: \") + diff.deleted.join(\", \"));\n }\n console.log();\n}\n\nfunction printPushReport(results: PushResult[], skippedPhases: string[]): void {\n const succeeded = results.filter((r) => r.success);\n const failed = results.filter((r) => !r.success);\n\n if (succeeded.length > 0) {\n console.log(chalk.green.bold(\"Succeeded:\"));\n for (const r of succeeded) {\n console.log(chalk.green(\" \" + r.action + \": \") + r.file);\n }\n }\n\n if (failed.length > 0) {\n console.log();\n console.log(chalk.red.bold(\"Failed:\"));\n for (const r of failed) {\n console.log(\n chalk.red(\" \" + r.action + \": \") +\n r.file +\n chalk.gray(\" — \" + (r.error ?? \"Unknown error\")),\n );\n }\n }\n\n if (skippedPhases.length > 0) {\n console.log();\n console.log(chalk.yellow.bold(\"Skipped phases:\"));\n for (const phase of skippedPhases) {\n console.log(chalk.yellow(\" \" + phase));\n }\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Command\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const pushCommand: Command = new Command(\"push\")\n .description(\"Push local portal content changes to the Fluid OS API\")\n .option(\"--yes\", \"Skip confirmation prompt\")\n .action(async (options: PushOptions) => {\n const cwd = process.cwd();\n const portalDir = join(cwd, PORTAL_DIR);\n const portalSyncDir = join(cwd, PORTAL_SYNC_DIR);\n\n console.log();\n console.log(chalk.blue.bold(\"Fluid Portal Push\"));\n console.log();\n\n // ── Check for portal directory ─────────────────────────────────────\n if (!existsSync(portalDir)) {\n console.log(\n chalk.red(\"Error:\") +\n \" No portal/ directory found. Run \" +\n chalk.cyan(\"fluid portal pull\") +\n \" first.\",\n );\n console.log();\n process.exit(1);\n }\n\n // ── Read snapshot ──────────────────────────────────────────────────\n const snapshot = await readSnapshot(portalSyncDir);\n if (!snapshot) {\n console.log(\n chalk.red(\"Error:\") +\n \" No snapshot found in .portal-sync/. Run \" +\n chalk.cyan(\"fluid portal pull\") +\n \" first.\",\n );\n console.log();\n process.exit(1);\n }\n\n // ── Read mappings ──────────────────────────────────────────────────\n const mappings = await readMappings(portalSyncDir);\n if (!mappings) {\n console.log(\n chalk.red(\"Error:\") +\n \" No mappings found in .portal-sync/. Run \" +\n chalk.cyan(\"fluid portal pull\") +\n \" first.\",\n );\n console.log();\n process.exit(1);\n }\n\n const definitionId = snapshot.definition_id;\n const definitionName = snapshot.definition;\n\n console.log(\n chalk.gray(\"Definition: \") +\n chalk.white(definitionName) +\n chalk.gray(` (ID: ${definitionId})`),\n );\n console.log();\n\n // ── Detect changes ─────────────────────────────────────────────────\n const spinner = ora();\n spinner.start(\"Detecting changes...\");\n\n const diff = await diffAgainstSnapshot(portalDir, snapshot);\n const totalChanges =\n diff.new.length + diff.changed.length + diff.deleted.length;\n\n if (totalChanges === 0) {\n spinner.succeed(\"Nothing to push.\");\n console.log();\n return;\n }\n\n spinner.succeed(`Found ${totalChanges} change(s)`);\n console.log();\n\n // ── Show changes and confirm ───────────────────────────────────────\n printChangesSummary(diff, definitionName);\n\n if (!options.yes) {\n const { confirmed } = await prompts({\n type: \"confirm\",\n name: \"confirmed\",\n message: `Push ${totalChanges} change(s) to Fluid OS?`,\n initial: false,\n });\n\n if (!confirmed) {\n console.log();\n console.log(chalk.gray(\"Push cancelled.\"));\n console.log();\n return;\n }\n console.log();\n }\n\n // ── Categorize changes ─────────────────────────────────────────────\n const changes = categorizeChanges(diff);\n\n // ── Cross-reference validation ─────────────────────────────────────\n spinner.start(\"Validating cross-references...\");\n const validationErrors = await validateCrossReferences(\n portalDir,\n mappings,\n changes,\n );\n\n if (validationErrors.length > 0) {\n spinner.fail(\"Cross-reference validation failed\");\n console.log();\n for (const err of validationErrors) {\n console.log(chalk.red(\" \" + err.file + \": \") + err.message);\n }\n console.log();\n process.exit(1);\n }\n spinner.succeed(\"Cross-references valid\");\n\n // ── Authenticate ───────────────────────────────────────────────────\n spinner.start(\"Authenticating...\");\n\n let client: FetchClient;\n try {\n client = createClient();\n spinner.succeed(\"Authenticated\");\n } catch (err) {\n spinner.fail(\"Authentication failed\");\n console.log();\n console.log(\n chalk.red(\"Error:\") +\n \" \" +\n (err instanceof Error ? err.message : String(err)),\n );\n console.log();\n process.exit(1);\n }\n\n // ── Phase 1: Screens + Themes (parallel) ───────────────────────────\n const allResults: PushResult[] = [];\n const skippedPhases: string[] = [];\n let currentMappings = mappings;\n let aborted = false;\n\n const hasScreenChanges =\n changes.screens.new.length > 0 ||\n changes.screens.changed.length > 0 ||\n changes.screens.deleted.length > 0;\n const hasThemeChanges =\n changes.themes.new.length > 0 ||\n changes.themes.changed.length > 0 ||\n changes.themes.deleted.length > 0;\n\n if (hasScreenChanges || hasThemeChanges) {\n spinner.start(\"Phase 1: Pushing screens and themes...\");\n\n const phase1Tasks: Promise<{\n results: PushResult[];\n mappings: PortalMappings;\n }>[] = [];\n\n if (hasScreenChanges) {\n phase1Tasks.push(\n pushScreens(\n client,\n definitionId,\n portalDir,\n changes.screens,\n currentMappings,\n ),\n );\n }\n if (hasThemeChanges) {\n phase1Tasks.push(\n pushThemes(\n client,\n definitionId,\n portalDir,\n changes.themes,\n currentMappings,\n ),\n );\n }\n\n const phase1Results = await Promise.all(phase1Tasks);\n\n // Merge mappings from both parallel operations\n // Only apply the resource type each operation actually owns\n for (const result of phase1Results) {\n allResults.push(...result.results);\n }\n if (hasScreenChanges) {\n currentMappings = {\n ...currentMappings,\n screens: phase1Results[0]!.mappings.screens,\n };\n }\n if (hasThemeChanges) {\n const idx = hasScreenChanges ? 1 : 0;\n currentMappings = {\n ...currentMappings,\n themes: phase1Results[idx]!.mappings.themes,\n };\n }\n\n const phase1Failed = phase1Results.some((r) =>\n r.results.some((res) => !res.success),\n );\n\n if (phase1Failed) {\n spinner.fail(\"Phase 1 failed\");\n aborted = true;\n skippedPhases.push(\"Phase 2: Navigations\", \"Phase 3: Profiles\");\n } else {\n spinner.succeed(\"Phase 1 complete\");\n }\n }\n\n // ── Phase 2: Navigations ───────────────────────────────────────────\n const hasNavChanges =\n changes.navigations.new.length > 0 ||\n changes.navigations.changed.length > 0 ||\n changes.navigations.deleted.length > 0;\n\n if (!aborted && hasNavChanges) {\n spinner.start(\"Phase 2: Pushing navigations...\");\n\n const navResult = await pushNavigations(\n client,\n definitionId,\n portalDir,\n changes.navigations,\n currentMappings,\n );\n\n allResults.push(...navResult.results);\n currentMappings = {\n ...currentMappings,\n navigations: navResult.mappings.navigations,\n };\n\n const phase2Failed = navResult.results.some((r) => !r.success);\n if (phase2Failed) {\n spinner.fail(\"Phase 2 failed\");\n aborted = true;\n skippedPhases.push(\"Phase 3: Profiles\");\n } else {\n spinner.succeed(\"Phase 2 complete\");\n }\n } else if (aborted && hasNavChanges) {\n // Already marked as skipped above\n }\n\n // ── Phase 3: Profiles ──────────────────────────────────────────────\n const hasProfileChanges =\n changes.profiles.new.length > 0 ||\n changes.profiles.changed.length > 0 ||\n changes.profiles.deleted.length > 0;\n\n if (!aborted && hasProfileChanges) {\n spinner.start(\"Phase 3: Pushing profiles...\");\n\n const profileResult = await pushProfiles(\n client,\n definitionId,\n portalDir,\n changes.profiles,\n currentMappings,\n );\n\n allResults.push(...profileResult.results);\n currentMappings = {\n ...currentMappings,\n profiles: profileResult.mappings.profiles,\n };\n\n const phase3Failed = profileResult.results.some((r) => !r.success);\n if (phase3Failed) {\n spinner.fail(\"Phase 3 failed\");\n } else {\n spinner.succeed(\"Phase 3 complete\");\n }\n }\n\n // ── Update mappings ────────────────────────────────────────────────\n await writeMappings(portalSyncDir, currentMappings);\n\n // ── Update snapshot for successfully pushed files ───────────────────\n const successfulFiles = new Set(\n allResults.filter((r) => r.success).map((r) => r.file),\n );\n\n if (successfulFiles.size > 0) {\n // Only advance snapshot entries for successfully pushed files;\n // leave skipped/failed entries at their original hashes so they\n // show up as changed on the next run.\n const updatedHashes = { ...snapshot.files };\n for (const file of successfulFiles) {\n const fullPath = join(portalDir, file);\n if (existsSync(fullPath)) {\n updatedHashes[file] = await computeFileHash(fullPath);\n } else {\n // deleted file — remove from snapshot\n delete updatedHashes[file];\n }\n }\n await writeSnapshot(portalSyncDir, {\n ...snapshot,\n files: updatedHashes,\n });\n }\n\n // ── Report ─────────────────────────────────────────────────────────\n console.log();\n const allSucceeded = allResults.every((r) => r.success);\n\n if (allSucceeded && !aborted) {\n console.log(chalk.green.bold(\"Push complete!\"));\n } else {\n console.log(chalk.yellow.bold(\"Push completed with issues:\"));\n }\n console.log();\n printPushReport(allResults, skippedPhases);\n console.log();\n });\n\nexport function registerPushCommand(ctx: PluginContext): void {\n ctx.program.addCommand(pushCommand);\n}\n","/**\n * Pure helper functions for widget scaffolding.\n * Extracted from widget-create command for testability.\n */\n\n/**\n * Convert kebab-case name to PascalCase widget type.\n * e.g., \"stock-ticker\" → \"StockTickerWidget\"\n */\nexport function toWidgetType(name: string): string {\n const pascal = name\n .split(\"-\")\n .map((s) => s.charAt(0).toUpperCase() + s.slice(1))\n .join(\"\");\n return pascal.endsWith(\"Widget\") ? pascal : `${pascal}Widget`;\n}\n\n/**\n * Derive the component name from a widget type.\n * Strips the trailing \"Widget\" suffix, but only if the result is non-empty\n * and starts with a letter (not a digit).\n * e.g., \"StockTickerWidget\" → \"StockTicker\"\n */\nexport function toComponentName(widgetType: string): string {\n if (widgetType === \"Widget\") return \"Widget\";\n const stripped = widgetType.replace(/Widget$/, \"\");\n return stripped || widgetType;\n}\n\n/**\n * Convert kebab-case name to a display name.\n * e.g., \"stock-ticker\" → \"Stock Ticker\"\n */\nexport function toDisplayName(name: string): string {\n return name\n .split(\"-\")\n .map((s) => s.charAt(0).toUpperCase() + s.slice(1))\n .join(\" \");\n}\n\n/**\n * Convert kebab-case to camelCase.\n * e.g., \"stock-ticker\" → \"stockTicker\"\n */\nexport function toCamelCase(name: string): string {\n return name.replace(/-./g, (x) => x.charAt(1).toUpperCase());\n}\n\n/**\n * Validate a widget name for scaffold.\n * Must be kebab-case, no trailing/consecutive dashes, no bare \"widget\".\n */\nexport function validateWidgetName(name: string): string | null {\n if (!/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(name)) {\n return \"Widget name must be kebab-case with no trailing or consecutive dashes (e.g., stock-ticker).\";\n }\n if (name === \"widget\") {\n return 'Widget name \"widget\" is reserved. Use a more descriptive name (e.g., custom-widget).';\n }\n return null;\n}\n\n/**\n * Insert an import line after the last import in a source file.\n * Skips if the import already exists (prevents duplicates on re-scaffold).\n * Returns null if no imports exist in the source.\n */\nexport function insertImport(\n source: string,\n importLine: string,\n): string | null {\n // Skip if import already exists\n if (source.includes(importLine)) return source;\n\n // Find the last real import statement (starts at column 0, not inside comments)\n const importPattern = /^import\\s/gm;\n let lastImportIndex = -1;\n let match: RegExpExecArray | null;\n while ((match = importPattern.exec(source)) !== null) {\n lastImportIndex = match.index;\n }\n if (lastImportIndex === -1) return null;\n\n const lineEnd = source.indexOf(\"\\n\", lastImportIndex);\n if (lineEnd === -1) {\n // Last import is on the final line with no trailing newline\n return source + \"\\n\" + importLine + \"\\n\";\n }\n\n return (\n source.slice(0, lineEnd + 1) + importLine + \"\\n\" + source.slice(lineEnd + 1)\n );\n}\n\n/**\n * Insert a manifest reference into the customWidgets array.\n * Preserves developer comments. Skips if already present.\n * Returns null if the array pattern isn't found.\n *\n * Searches for the LAST `export const customWidgets` declaration to skip\n * matches inside JSDoc @example blocks.\n */\nexport function insertIntoCustomWidgets(\n source: string,\n camelName: string,\n): string | null {\n // Find all matches and use the last one (the real declaration, not JSDoc examples).\n // The type annotation may span multiple lines (e.g., `import(\"...\").WidgetManifest[]`),\n // so we use [\\s\\S] to match across newlines between the declaration and the `= [`.\n const pattern =\n /(export const customWidgets(?::[\\s\\S]*?)?\\s*=\\s*)\\[([^\\]]*)\\]/g;\n let lastMatch: RegExpExecArray | null = null;\n let m: RegExpExecArray | null;\n while ((m = pattern.exec(source)) !== null) {\n lastMatch = m;\n }\n\n if (!lastMatch) return null;\n\n const fullMatch = lastMatch[0];\n const declaration = lastMatch[1]!;\n const inner = lastMatch[2]!;\n const matchStart = lastMatch.index;\n\n const lines = inner.split(\"\\n\");\n\n // Collect existing real entries (stripped of commas for comparison)\n const existingEntries: string[] = [];\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed && !trimmed.startsWith(\"//\")) {\n existingEntries.push(trimmed.replace(/,$/, \"\"));\n }\n }\n\n // Skip if already registered\n if (existingEntries.includes(camelName)) {\n return source;\n }\n\n // Preserve comment lines\n const commentLines = lines\n .filter((line) => line.trim().startsWith(\"//\"))\n .map((line) => line.trimEnd());\n\n const commentBlock =\n commentLines.length > 0 ? \"\\n\" + commentLines.join(\"\\n\") : \"\";\n\n // Build entry lines with consistent 2-space indentation\n const allEntries = [...existingEntries, camelName];\n const entryBlock = allEntries.map((e) => ` ${e},`).join(\"\\n\");\n\n const replacement = `${declaration}[${commentBlock}\\n${entryBlock}\\n]`;\n\n return (\n source.slice(0, matchStart) +\n replacement +\n source.slice(matchStart + fullMatch.length)\n );\n}\n","import { Command } from \"commander\";\nimport type { PluginContext } from \"@fluid-app/fluid-cli\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport path from \"node:path\";\nimport type { WidgetCreateOptions } from \"../types.js\";\nimport {\n toWidgetType,\n toComponentName,\n toDisplayName,\n toCamelCase,\n validateWidgetName,\n insertImport,\n insertIntoCustomWidgets,\n} from \"../utils/widget-helpers.js\";\n\nconst createSubcommand = new Command(\"create\")\n .description(\"Scaffold a new custom widget\")\n .argument(\"<name>\", \"Widget name in kebab-case (e.g., stock-ticker)\")\n .option(\n \"-c, --category <category>\",\n \"Widget category for palette grouping\",\n \"components\",\n )\n .action(async (name: string, options: WidgetCreateOptions) => {\n const cwd = process.cwd();\n const widgetDir = path.join(cwd, \"src\", \"widgets\", name);\n\n // Validate name format\n const validationError = validateWidgetName(name);\n if (validationError) {\n console.error(chalk.red(`Error: ${validationError}`));\n process.exit(1);\n }\n\n // Check we're in a Fluid portal project\n if (!fs.existsSync(path.join(cwd, \"src\", \"portal.config.ts\"))) {\n console.error(chalk.red(\"Error: No src/portal.config.ts found.\"));\n console.error(\n chalk.yellow(\"Run this command from a Fluid portal project root.\"),\n );\n process.exit(1);\n }\n\n // Check widget doesn't already exist\n if (fs.existsSync(widgetDir)) {\n console.error(\n chalk.red(\n `Error: Widget directory already exists: src/widgets/${name}`,\n ),\n );\n process.exit(1);\n }\n\n const widgetType = toWidgetType(name);\n const componentName = toComponentName(widgetType);\n const displayName = toDisplayName(name);\n const category = options.category ?? \"components\";\n\n // Create widget directory and write files — clean up on failure\n try {\n await fs.ensureDir(widgetDir);\n\n await fs.writeFile(\n path.join(widgetDir, \"component.tsx\"),\n `interface ${widgetType}Props {\n title?: string;\n}\n\nexport function ${componentName}({ title = \"${displayName}\" }: ${widgetType}Props) {\n return (\n <div className=\"p-4\">\n <h3 className=\"text-lg font-semibold\">{title}</h3>\n <p className=\"text-sm text-gray-500\">\n Edit this widget in src/widgets/${name}/component.tsx\n </p>\n </div>\n );\n}\n`,\n );\n\n await fs.writeFile(\n path.join(widgetDir, \"manifest.ts\"),\n `import type { WidgetManifest } from \"@fluid-app/portal-sdk\";\nimport { ${componentName} } from \"./component\";\n\nexport const manifest: WidgetManifest = {\n manifestVersion: 1,\n type: \"${widgetType}\",\n component: ${componentName},\n displayName: \"${displayName}\",\n description: \"A custom ${displayName.toLowerCase()} widget\",\n icon: \"puzzle-piece\",\n category: \"${category}\",\n propertySchema: {\n widgetType: \"${widgetType}\",\n displayName: \"${displayName}\",\n fields: [{ key: \"title\", label: \"Title\", type: \"text\" }],\n },\n defaultProps: {\n title: \"${displayName}\",\n },\n};\n`,\n );\n\n await fs.writeFile(\n path.join(widgetDir, \"index.ts\"),\n `export { ${componentName} } from \"./component\";\nexport { manifest } from \"./manifest\";\n`,\n );\n } catch (err) {\n await fs.remove(widgetDir).catch(() => {});\n console.error(chalk.red(\"Error: Failed to scaffold widget files.\"));\n console.error(err);\n process.exit(1);\n }\n\n // Auto-register in portal.config.ts\n const configPath = path.join(cwd, \"src\", \"portal.config.ts\");\n const camelName = toCamelCase(name);\n const importLine = `import { manifest as ${camelName} } from \"./widgets/${name}\";`;\n\n const configSource = await fs.readFile(configPath, \"utf-8\");\n\n const withImport = insertImport(configSource, importLine);\n if (withImport === null) {\n console.warn(\n chalk.yellow(\n \"Warning: Could not find import statements in portal.config.ts. \" +\n \"Add the import manually:\",\n ),\n );\n console.warn(chalk.cyan(` ${importLine}`));\n }\n\n let updated = insertIntoCustomWidgets(\n withImport ?? configSource,\n camelName,\n );\n if (updated === null) {\n if (withImport === null) {\n // Neither the import nor the array could be placed — warn and bail\n // to avoid writing a broken config with an undefined identifier\n console.warn(\n chalk.yellow(\n \"Warning: Could not register widget in portal.config.ts. Add manually:\",\n ),\n );\n console.warn(chalk.cyan(` ${importLine}`));\n console.warn(chalk.cyan(` customWidgets: [..., ${camelName}]`));\n } else {\n // Import succeeded but customWidgets array doesn't exist yet — create it\n updated =\n withImport.trimEnd() +\n `\\n\\nexport const customWidgets = [${camelName}];\\n`;\n }\n }\n\n if (updated !== null) {\n await fs.writeFile(configPath, updated, \"utf-8\");\n } else if (withImport !== null) {\n await fs.writeFile(configPath, withImport, \"utf-8\");\n }\n\n console.log();\n console.log(chalk.green(\"Created widget:\") + ` src/widgets/${name}/`);\n console.log(chalk.gray(\" component.tsx — React component\"));\n console.log(chalk.gray(\" manifest.ts — WidgetManifest\"));\n console.log(chalk.gray(\" index.ts — Re-exports\"));\n console.log();\n if (updated !== null) {\n console.log(\n chalk.green(\"Registered\") + ` in ${chalk.cyan(\"src/portal.config.ts\")}`,\n );\n console.log();\n }\n console.log(chalk.yellow(\"Next steps:\"));\n console.log(\n ` 1. Edit the component in ${chalk.cyan(`src/widgets/${name}/component.tsx`)}`,\n );\n console.log(\n ` 2. Customize the manifest fields in ${chalk.cyan(`src/widgets/${name}/manifest.ts`)}`,\n );\n console.log(\n ` 3. Run ${chalk.cyan(\"fluid portal dev\")} to preview in the builder`,\n );\n });\n\nexport const widgetCommand: Command = new Command(\"widget\")\n .description(\"Manage custom portal widgets\")\n .addCommand(createSubcommand);\n\nexport function registerWidgetCommand(ctx: PluginContext): void {\n ctx.program.addCommand(widgetCommand);\n}\n","import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { createHash } from \"node:crypto\";\n\nexport const WIDGET_PACKAGE_BUILDER_VERSION = \"1\";\n\nexport interface ArtifactMetadata {\n readonly path: string;\n readonly sha256: string;\n readonly bytes: number;\n readonly contentType: string;\n}\n\nexport interface PublishManifestMetadata {\n readonly packageId: string;\n readonly version: string;\n readonly builderVersion: string;\n readonly cliVersion: string;\n readonly runtimeVersion: string;\n readonly manifestHash: string;\n readonly artifacts: readonly ArtifactMetadata[];\n}\n\nconst CONTENT_TYPES: Readonly<Record<string, string>> = {\n \".css\": \"text/css\",\n \".js\": \"application/javascript\",\n \".json\": \"application/json\",\n \".map\": \"application/json\",\n};\nconst CSS_ARTIFACT_PATH_PATTERN = /^[A-Za-z0-9._~-]+\\.css$/;\nconst JS_MAP_ARTIFACT_PATH_PATTERN = /^[A-Za-z0-9._~-]+\\.js\\.map$/;\n\nexport async function computeArtifactMetadata(\n filePath: string,\n baseDir: string,\n): Promise<ArtifactMetadata> {\n const relativePath = toPosixPath(path.relative(baseDir, filePath));\n assertAllowedArtifactPath(relativePath);\n await assertRegularArtifactFile(filePath, relativePath);\n const buffer = await fs.readFile(filePath);\n\n return {\n path: relativePath,\n sha256: sha256(buffer),\n bytes: buffer.byteLength,\n contentType: getArtifactContentType(filePath),\n };\n}\n\nexport async function collectWidgetPackageArtifacts(\n publishDir: string,\n): Promise<ArtifactMetadata[]> {\n const artifactPaths = await findArtifactPaths(publishDir);\n const artifacts = await Promise.all(\n artifactPaths.map((artifactPath) =>\n computeArtifactMetadata(artifactPath, publishDir),\n ),\n );\n\n assertRequiredUploadArtifacts(artifacts);\n\n return artifacts.sort((a, b) => a.path.localeCompare(b.path));\n}\n\nexport function createPublishManifestMetadata(options: {\n readonly packageId: string;\n readonly version: string;\n readonly cliVersion: string;\n readonly runtimeVersion: string;\n readonly manifestContent: string | Buffer;\n readonly artifacts: readonly ArtifactMetadata[];\n readonly builderVersion?: string;\n}): PublishManifestMetadata {\n return {\n packageId: options.packageId,\n version: options.version,\n builderVersion: options.builderVersion ?? WIDGET_PACKAGE_BUILDER_VERSION,\n cliVersion: options.cliVersion,\n runtimeVersion: options.runtimeVersion,\n manifestHash: sha256(options.manifestContent),\n artifacts: options.artifacts,\n };\n}\n\nexport function getArtifactContentType(filePath: string): string {\n const basename = path.basename(filePath);\n if (basename.endsWith(\".js.map\")) {\n return \"application/json\";\n }\n return CONTENT_TYPES[path.extname(filePath)] ?? \"application/octet-stream\";\n}\n\nexport function sha256(content: string | Buffer): string {\n return createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\nexport function isWidgetPackageCssArtifactPath(relativePath: string): boolean {\n return CSS_ARTIFACT_PATH_PATTERN.test(relativePath);\n}\n\nexport function isWidgetPackageJsMapArtifactPath(\n relativePath: string,\n): boolean {\n return JS_MAP_ARTIFACT_PATH_PATTERN.test(relativePath);\n}\n\nasync function assertRegularArtifactFile(\n filePath: string,\n relativePath: string,\n): Promise<void> {\n const stat = await fs.lstat(filePath);\n if (stat.isSymbolicLink()) {\n throw new Error(\n `Widget publish artifact ${JSON.stringify(relativePath)} must be a regular file and must not be a symbolic link.`,\n );\n }\n if (!stat.isFile()) {\n throw new Error(\n `Widget publish artifact ${JSON.stringify(relativePath)} must be a regular file.`,\n );\n }\n}\n\nasync function findArtifactPaths(\n dir: string,\n baseDir: string = dir,\n): Promise<string[]> {\n if (!(await fs.pathExists(dir))) return [];\n\n const entries = await fs.readdir(dir, { withFileTypes: true });\n const paths = await Promise.all(\n entries.map(async (entry) => {\n const entryPath = path.join(dir, entry.name);\n const relativePath = toPosixPath(path.relative(baseDir, entryPath));\n\n if (entry.isSymbolicLink()) {\n throw new Error(\n `Widget publish artifact ${JSON.stringify(relativePath)} must be a regular file and must not be a symbolic link.`,\n );\n }\n\n if (isUploadArtifact(relativePath)) {\n if (!entry.isFile()) {\n throw new Error(\n `Widget publish artifact ${JSON.stringify(relativePath)} must be a regular file.`,\n );\n }\n return [entryPath];\n }\n\n if (entry.isDirectory()) {\n const nestedPaths = await findArtifactPaths(entryPath, baseDir);\n if (nestedPaths.length === 0) {\n throwUnsupportedArtifactPath(`${relativePath}/`);\n }\n return nestedPaths;\n }\n if (isAllowedGeneratedFile(relativePath)) return [];\n throwUnsupportedArtifactPath(relativePath);\n }),\n );\n\n return paths.flat();\n}\n\nfunction assertRequiredUploadArtifacts(\n artifacts: readonly ArtifactMetadata[],\n): void {\n const artifactPaths = new Set(artifacts.map((artifact) => artifact.path));\n for (const requiredPath of [\"widget.js\", \"manifest.json\"] as const) {\n if (artifactPaths.has(requiredPath)) continue;\n throw new Error(\n `Widget package publish output must include regular file ${JSON.stringify(requiredPath)}.`,\n );\n }\n}\n\nfunction assertAllowedArtifactPath(relativePath: string): void {\n if (isUploadArtifact(relativePath) || isAllowedGeneratedFile(relativePath))\n return;\n throwUnsupportedArtifactPath(relativePath);\n}\n\nfunction isUploadArtifact(relativePath: string): boolean {\n return (\n relativePath === \"widget.js\" ||\n relativePath === \"manifest.json\" ||\n isWidgetPackageCssArtifactPath(relativePath) ||\n isWidgetPackageJsMapArtifactPath(relativePath)\n );\n}\n\nfunction isAllowedGeneratedFile(relativePath: string): boolean {\n return (\n isFlatArtifactPath(relativePath) && relativePath === \"publish-manifest.json\"\n );\n}\n\nfunction isFlatArtifactPath(relativePath: string): boolean {\n return (\n relativePath.length > 0 &&\n !relativePath.includes(\"/\") &&\n !relativePath.includes(\"\\\\\")\n );\n}\n\nfunction throwUnsupportedArtifactPath(relativePath: string): never {\n throw new Error(\n `Unsupported widget publish artifact ${JSON.stringify(relativePath)}. ` +\n \"Allowed files are widget.js, manifest.json, top-level [A-Za-z0-9._~-]+.css, top-level [A-Za-z0-9._~-]+.js.map, and publish-manifest.json.\",\n );\n}\n\nfunction toPosixPath(value: string): string {\n return value.split(path.sep).join(\"/\");\n}\n","import { isWidgetPackageCssArtifactPath } from \"./widget-package-artifacts.js\";\n\nconst URL_SAFE_SEGMENT_SOURCE = \"[A-Za-z0-9][A-Za-z0-9_~-]*\";\nconst URL_SAFE_WIDGET_NAME_PATTERN = new RegExp(`^${URL_SAFE_SEGMENT_SOURCE}$`);\nconst URL_SAFE_DOTTED_IDENTIFIER_PATTERN = new RegExp(\n `^${URL_SAFE_SEGMENT_SOURCE}(?:\\\\.${URL_SAFE_SEGMENT_SOURCE})*$`,\n);\nconst SEMVER_CORE_PATTERN = \"(0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)\";\nconst SEMVER_PRERELEASE_IDENTIFIER_PATTERN =\n \"(?:0|[1-9]\\\\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*)\";\nconst SEMVER_URL_SAFE_PATTERN = new RegExp(\n `^${SEMVER_CORE_PATTERN}(?:-${SEMVER_PRERELEASE_IDENTIFIER_PATTERN}(?:\\\\.${SEMVER_PRERELEASE_IDENTIFIER_PATTERN})*)?$`,\n);\nconst WIDGET_PACKAGE_MANIFEST_VERSION = 1;\nconst DEFAULT_WIDGET_ICON = \"box\";\nconst DEFAULT_WIDGET_CATEGORY = \"components\";\nconst DEFAULT_WIDGET_CONTAINER = \"block\";\nconst DEFAULT_MIN_SDK_VERSION = \"0.0.0\";\n\nexport type WidgetPackageOwnerKind = \"company\" | \"droplet\";\n\nexport type WidgetRuntimeContainer = \"inline\" | \"block\" | \"card\" | \"fullscreen\";\nexport type WidgetRuntimeResizable =\n | boolean\n | \"horizontal\"\n | \"vertical\"\n | \"both\";\n\nexport interface SourceWidgetMetadata {\n readonly name: string;\n readonly displayName?: string;\n readonly description?: string;\n readonly icon?: string;\n readonly category?: string;\n readonly propertySchema?: Record<string, unknown>;\n readonly defaultProps?: Record<string, unknown>;\n readonly container?: unknown;\n readonly minSdkVersion?: string;\n readonly resizable?: unknown;\n}\n\nexport interface SourceWidgetPackageMetadata {\n readonly manifestVersion?: number;\n readonly scope?: string;\n readonly packageStableId?: string;\n readonly packageId: string;\n readonly packageType?: string;\n readonly version: string;\n readonly widgets: readonly SourceWidgetMetadata[];\n readonly cssUrls?: readonly string[];\n}\n\nexport interface WidgetDescriptorMetadata {\n readonly type: string;\n readonly name: string;\n readonly displayName: string;\n readonly description: string;\n readonly icon: string;\n readonly category: string;\n readonly propertySchema: Record<string, unknown>;\n readonly defaultProps: Record<string, unknown>;\n readonly container: WidgetRuntimeContainer;\n readonly minSdkVersion: string;\n readonly resizable: WidgetRuntimeResizable;\n}\n\nexport interface WidgetPackageDescriptorMetadata {\n readonly manifestVersion: 1;\n readonly packageId: string;\n readonly packageType: WidgetPackageOwnerKind;\n readonly version: string;\n readonly remoteEntryUrl: string;\n readonly cssUrls: readonly string[];\n readonly widgets: readonly WidgetDescriptorMetadata[];\n}\n\nexport interface ValidatedWidgetPackageBuild {\n readonly sourcePackage: SourceWidgetPackageMetadata;\n readonly packageKey: string;\n readonly packageId: string;\n readonly owner: WidgetPackageOwnerKind;\n readonly version: string;\n readonly widgets: readonly WidgetDescriptorMetadata[];\n}\n\nexport type WidgetPackageValidationErrorCode =\n | \"NO_SOURCE_PACKAGE\"\n | \"MULTIPLE_SOURCE_PACKAGES\"\n | \"INVALID_SOURCE_PACKAGE\"\n | \"INVALID_WIDGET_METADATA\"\n | \"UNSUPPORTED_OWNER\"\n | \"INVALID_PACKAGE_KEY\"\n | \"INVALID_VERSION\"\n | \"NO_WIDGETS\"\n | \"INVALID_WIDGET_NAME\"\n | \"INVALID_WIDGET_TYPE\"\n | \"DUPLICATE_WIDGET\";\n\nexport interface WidgetPackageValidationError {\n readonly code: WidgetPackageValidationErrorCode;\n readonly message: string;\n readonly path?: string;\n}\n\nexport interface WidgetPackageValidationResult {\n readonly success: boolean;\n readonly value?: ValidatedWidgetPackageBuild;\n readonly errors: readonly WidgetPackageValidationError[];\n}\n\nexport interface ValidateSourceWidgetPackageOptions {\n readonly owner?: WidgetPackageOwnerKind;\n}\n\nexport function validateSingleSourceWidgetPackage(\n sourcePackages: readonly unknown[],\n options: ValidateSourceWidgetPackageOptions = {},\n): WidgetPackageValidationResult {\n if (sourcePackages.length === 0) {\n return validationFailure({\n code: \"NO_SOURCE_PACKAGE\",\n message:\n \"No defineWidgetPackage source package was found. Export widgetPackage, widgetPackages, or a default widget package from src/widgets.config.ts, src/portal.config.ts, or portal.config.ts.\",\n });\n }\n\n if (sourcePackages.length > 1) {\n return validationFailure({\n code: \"MULTIPLE_SOURCE_PACKAGES\",\n message:\n \"Publish/deploy supports exactly one defineWidgetPackage source package. Export one package or split packages into separate builds.\",\n });\n }\n\n const sourcePackageValue = sourcePackages[0];\n if (!sourcePackageValue) {\n return validationFailure({\n code: \"NO_SOURCE_PACKAGE\",\n message: \"No defineWidgetPackage source package was found.\",\n });\n }\n\n const shapeErrors = validateSourcePackageShape(sourcePackageValue);\n if (shapeErrors.length > 0) {\n return { success: false, errors: shapeErrors };\n }\n const sourcePackage = sourcePackageValue as SourceWidgetPackageMetadata;\n\n const errors: WidgetPackageValidationError[] = [];\n const owner = options.owner ?? sourcePackage.packageType;\n if (owner !== \"company\" && owner !== \"droplet\") {\n errors.push({\n code: \"UNSUPPORTED_OWNER\",\n path: \"packageType\",\n message:\n 'Widget package publish/deploy currently supports company and droplet owners. Set packageType to \"company\" or \"droplet\".',\n });\n }\n\n const resolvedOwner = owner === \"droplet\" ? \"droplet\" : \"company\";\n const packageKey = resolvePackageKey(sourcePackage, resolvedOwner);\n const packageKeyPath = readNonEmptyTrimmedString(\n sourcePackage.packageStableId,\n )\n ? \"packageStableId\"\n : \"packageId\";\n if (!isUrlSafeDottedIdentifier(packageKey)) {\n errors.push({\n code: \"INVALID_PACKAGE_KEY\",\n path: packageKeyPath,\n message:\n \"Widget package key must be URL-safe dot-separated text (letters, numbers, '.', '_', '~', and '-' only).\",\n });\n }\n\n if (!isUrlSafeSemver(sourcePackage.version)) {\n errors.push({\n code: \"INVALID_VERSION\",\n path: \"version\",\n message:\n \"Widget package version must be a URL-safe SemVer version without build metadata (for example 1.2.3 or 1.2.3-beta.1).\",\n });\n }\n\n if (sourcePackage.widgets.length === 0) {\n errors.push({\n code: \"NO_WIDGETS\",\n path: \"widgets\",\n message: \"Widget package must include at least one widget.\",\n });\n }\n\n const packageId = `${resolvedOwner}.${packageKey}`;\n const seenNames = new Set<string>();\n const seenTypes = new Set<string>();\n const widgets: WidgetDescriptorMetadata[] = [];\n\n sourcePackage.widgets.forEach((widget, index) => {\n const path = `widgets[${index}]`;\n if (!isUrlSafeWidgetName(widget.name)) {\n errors.push({\n code: \"INVALID_WIDGET_NAME\",\n path: `${path}.name`,\n message:\n \"Widget name must be URL-safe text (letters, numbers, '_', '~', and '-' only) and cannot be empty.\",\n });\n return;\n }\n\n if (seenNames.has(widget.name)) {\n errors.push({\n code: \"DUPLICATE_WIDGET\",\n path: `${path}.name`,\n message: `Duplicate widget name \"${widget.name}\" found in package ${packageKey}.`,\n });\n return;\n }\n seenNames.add(widget.name);\n\n const type = `${packageId}.${widget.name}`;\n if (!isUrlSafeDottedIdentifier(type)) {\n errors.push({\n code: \"INVALID_WIDGET_TYPE\",\n path: `${path}.type`,\n message: `Generated widget type \"${type}\" is not URL-safe.`,\n });\n return;\n }\n\n if (seenTypes.has(type)) {\n errors.push({\n code: \"DUPLICATE_WIDGET\",\n path: `${path}.type`,\n message: `Duplicate generated widget type \"${type}\" found.`,\n });\n return;\n }\n seenTypes.add(type);\n\n widgets.push(sourceWidgetToDescriptor(widget, type));\n });\n\n if (errors.length > 0) return { success: false, errors };\n\n return {\n success: true,\n value: {\n sourcePackage,\n packageKey,\n packageId,\n owner: resolvedOwner,\n version: sourcePackage.version,\n widgets,\n },\n errors: [],\n };\n}\n\nexport function buildWidgetPackageDescriptor(\n validated: ValidatedWidgetPackageBuild,\n options: {\n readonly remoteEntryUrl?: string;\n readonly cssUrls?: readonly string[];\n } = {},\n): WidgetPackageDescriptorMetadata {\n const remoteEntryUrl = options.remoteEntryUrl ?? \"widget.js\";\n validateRuntimeDescriptorUrl(remoteEntryUrl, \"remoteEntryUrl\");\n\n return {\n manifestVersion: WIDGET_PACKAGE_MANIFEST_VERSION,\n packageId: getWidgetPackageDescriptorPackageId(validated),\n packageType: validated.owner,\n version: validated.version,\n remoteEntryUrl,\n cssUrls: mergeCssUrls(validated.sourcePackage.cssUrls, options.cssUrls),\n widgets: validated.widgets,\n };\n}\n\nexport function getWidgetPackageDescriptorPackageId(\n validated: ValidatedWidgetPackageBuild,\n): string {\n return validated.owner === \"droplet\"\n ? validated.packageKey\n : validated.packageId;\n}\n\nfunction sourceWidgetToDescriptor(\n widget: SourceWidgetMetadata,\n type: string,\n): WidgetDescriptorMetadata {\n const displayName = widget.displayName ?? widget.name;\n\n return {\n type,\n name: widget.name,\n displayName,\n description: widget.description ?? `Custom widget ${displayName}`,\n icon: widget.icon ?? DEFAULT_WIDGET_ICON,\n category: widget.category ?? DEFAULT_WIDGET_CATEGORY,\n propertySchema: normalizePropertySchema(widget.propertySchema, type),\n defaultProps: widget.defaultProps ?? {},\n container: normalizeContainer(widget.container),\n minSdkVersion: widget.minSdkVersion ?? DEFAULT_MIN_SDK_VERSION,\n resizable: normalizeResizable(widget.resizable),\n };\n}\n\nfunction validationFailure(\n error: WidgetPackageValidationError,\n): WidgetPackageValidationResult {\n return { success: false, errors: [error] };\n}\n\nfunction validateSourcePackageShape(\n value: unknown,\n): WidgetPackageValidationError[] {\n if (!isRecord(value)) {\n return [\n {\n code: \"INVALID_SOURCE_PACKAGE\",\n message: \"Widget source package must be a JSON object.\",\n },\n ];\n }\n\n const errors: WidgetPackageValidationError[] = [];\n requireStringField(value, \"packageId\", \"packageId\", errors);\n requireStringField(value, \"version\", \"version\", errors);\n validateOptionalStringField(value, \"scope\", \"scope\", errors);\n validateOptionalStringField(\n value,\n \"packageStableId\",\n \"packageStableId\",\n errors,\n );\n validateOptionalStringField(value, \"packageType\", \"packageType\", errors);\n\n if (value.cssUrls !== undefined) {\n if (!Array.isArray(value.cssUrls)) {\n errors.push({\n code: \"INVALID_SOURCE_PACKAGE\",\n path: \"cssUrls\",\n message:\n \"Widget package cssUrls must be an array of strings when present.\",\n });\n } else {\n value.cssUrls.forEach((cssUrl, index) => {\n validateCssUrl(cssUrl, `cssUrls[${index}]`, errors);\n });\n }\n }\n\n if (!Array.isArray(value.widgets)) {\n errors.push({\n code: \"INVALID_SOURCE_PACKAGE\",\n path: \"widgets\",\n message: \"Widget package widgets must be an array.\",\n });\n return errors;\n }\n\n value.widgets.forEach((widget, index) => {\n const widgetPath = `widgets[${index}]`;\n if (!isRecord(widget)) {\n errors.push({\n code: \"INVALID_WIDGET_METADATA\",\n path: widgetPath,\n message: \"Widget metadata must be a JSON object.\",\n });\n return;\n }\n\n requireStringField(widget, \"name\", `${widgetPath}.name`, errors, {\n code: \"INVALID_WIDGET_NAME\",\n message: \"Widget name must be a string and cannot be empty.\",\n });\n validateOptionalStringField(\n widget,\n \"displayName\",\n `${widgetPath}.displayName`,\n errors,\n { requireNonEmpty: true },\n );\n validateOptionalStringField(\n widget,\n \"description\",\n `${widgetPath}.description`,\n errors,\n { requireNonEmpty: true },\n );\n validateOptionalStringField(widget, \"icon\", `${widgetPath}.icon`, errors, {\n requireNonEmpty: true,\n });\n validateOptionalStringField(\n widget,\n \"category\",\n `${widgetPath}.category`,\n errors,\n { requireNonEmpty: true },\n );\n validateOptionalStringField(\n widget,\n \"minSdkVersion\",\n `${widgetPath}.minSdkVersion`,\n errors,\n { requireNonEmpty: true },\n );\n validateOptionalRecordField(\n widget,\n \"propertySchema\",\n `${widgetPath}.propertySchema`,\n errors,\n );\n validateOptionalRecordField(\n widget,\n \"defaultProps\",\n `${widgetPath}.defaultProps`,\n errors,\n );\n });\n\n return errors;\n}\n\nfunction requireStringField(\n record: Record<string, unknown>,\n key: string,\n path: string,\n errors: WidgetPackageValidationError[],\n override?: Pick<WidgetPackageValidationError, \"code\" | \"message\">,\n): void {\n const value = record[key];\n if (typeof value === \"string\" && value.trim().length > 0) return;\n\n errors.push({\n code: override?.code ?? \"INVALID_SOURCE_PACKAGE\",\n path,\n message:\n override?.message ?? `${path} must be a string and cannot be empty.`,\n });\n}\n\nfunction validateOptionalStringField(\n record: Record<string, unknown>,\n key: string,\n path: string,\n errors: WidgetPackageValidationError[],\n options: { readonly requireNonEmpty?: boolean } = {},\n): void {\n const value = record[key];\n if (value === undefined) return;\n if (typeof value === \"string\") {\n if (!options.requireNonEmpty || value.trim().length > 0) return;\n errors.push({\n code: \"INVALID_SOURCE_PACKAGE\",\n path,\n message: `${path} must be a non-empty string when present.`,\n });\n return;\n }\n\n errors.push({\n code: \"INVALID_SOURCE_PACKAGE\",\n path,\n message: `${path} must be a string when present.`,\n });\n}\n\nfunction validateCssUrl(\n value: unknown,\n cssUrlPath: string,\n errors: WidgetPackageValidationError[],\n): void {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n errors.push({\n code: \"INVALID_SOURCE_PACKAGE\",\n path: cssUrlPath,\n message: \"Widget package cssUrls entries must be non-empty strings.\",\n });\n return;\n }\n\n if (!isValidRuntimeDescriptorUrl(value)) {\n errors.push({\n code: \"INVALID_SOURCE_PACKAGE\",\n path: cssUrlPath,\n message:\n \"Widget package cssUrls entries must be https URLs, trusted local http URLs, or relative URLs.\",\n });\n return;\n }\n\n if (!isAbsoluteRuntimeUrl(value) && !isWidgetPackageCssArtifactPath(value)) {\n errors.push({\n code: \"INVALID_SOURCE_PACKAGE\",\n path: cssUrlPath,\n message:\n \"Widget package relative cssUrls entries must be top-level CSS artifact filenames matching [A-Za-z0-9._~-]+.css.\",\n });\n }\n}\n\nfunction validateRuntimeDescriptorUrl(value: string, urlPath: string): void {\n if (value.trim().length === 0) {\n throw new Error(`${urlPath} must be a non-empty string.`);\n }\n\n if (!isValidRuntimeDescriptorUrl(value)) {\n throw new Error(\n `${urlPath} must be an https URL, trusted local http URL, or relative URL.`,\n );\n }\n}\n\nfunction isValidRuntimeDescriptorUrl(value: string): boolean {\n if (value.trim() !== value || containsUnsafeUrlCharacter(value)) return false;\n\n const schemeMatch = /^[a-zA-Z][a-zA-Z\\d+.-]*:/.exec(value);\n if (schemeMatch) {\n let parsedUrl: URL;\n try {\n parsedUrl = new URL(value);\n } catch {\n return false;\n }\n\n return (\n parsedUrl.protocol === \"https:\" || isTrustedLocalHttpUrl(parsedUrl, value)\n );\n }\n\n if (value.slice(0, 2) === \"//\") return false;\n\n try {\n void new URL(value, \"http://localhost\");\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isTrustedLocalHttpUrl(url: URL, rawUrl: string): boolean {\n if (url.protocol !== \"http:\") return false;\n\n const hostname = extractRawHostname(rawUrl).toLowerCase();\n return (\n hostname === \"localhost\" ||\n hostname === \"[::1]\" ||\n hostname === \"::1\" ||\n isLoopbackIpv4Hostname(hostname)\n );\n}\n\nfunction extractRawHostname(rawUrl: string): string {\n const authorityStart = rawUrl.indexOf(\"://\") + 3;\n const authorityEnd = findAuthorityEnd(rawUrl, authorityStart);\n const authority = rawUrl.slice(authorityStart, authorityEnd);\n const hostAndPort = authority.slice(authority.lastIndexOf(\"@\") + 1);\n\n if (hostAndPort.charAt(0) === \"[\") {\n const bracketEnd = hostAndPort.indexOf(\"]\");\n return bracketEnd === -1\n ? hostAndPort\n : hostAndPort.slice(0, bracketEnd + 1);\n }\n\n const portStart = hostAndPort.indexOf(\":\");\n return portStart === -1 ? hostAndPort : hostAndPort.slice(0, portStart);\n}\n\nfunction findAuthorityEnd(rawUrl: string, authorityStart: number): number {\n let authorityEnd = rawUrl.length;\n for (const delimiter of [\"/\", \"?\", \"#\"] as const) {\n const delimiterIndex = rawUrl.indexOf(delimiter, authorityStart);\n if (delimiterIndex !== -1 && delimiterIndex < authorityEnd) {\n authorityEnd = delimiterIndex;\n }\n }\n return authorityEnd;\n}\n\nfunction isLoopbackIpv4Hostname(hostname: string): boolean {\n const octets = hostname.split(\".\");\n if (octets.length !== 4 || octets[0] !== \"127\") return false;\n\n return octets.every(isBoundedIpv4Octet);\n}\n\nfunction isBoundedIpv4Octet(octet: string): boolean {\n if (!/^\\d{1,3}$/.test(octet)) return false;\n if (octet.length > 1 && octet.charAt(0) === \"0\") return false;\n\n const value = Number(octet);\n return value >= 0 && value <= 255;\n}\n\nfunction containsUnsafeUrlCharacter(value: string): boolean {\n for (let index = 0; index < value.length; index += 1) {\n const charCode = value.charCodeAt(index);\n if (charCode <= 0x1f || charCode === 0x7f || charCode === 0x5c) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction validateOptionalRecordField(\n record: Record<string, unknown>,\n key: string,\n path: string,\n errors: WidgetPackageValidationError[],\n): void {\n const value = record[key];\n if (value === undefined || isRecord(value)) return;\n\n errors.push({\n code: \"INVALID_WIDGET_METADATA\",\n path,\n message: `${path} must be a JSON object when present.`,\n });\n}\n\nfunction mergeCssUrls(\n sourceCssUrls: readonly string[] | undefined,\n generatedCssUrls: readonly string[] | undefined,\n): string[] {\n const generatedCssUrlSet = new Set(generatedCssUrls ?? []);\n sourceCssUrls?.forEach((cssUrl, index) => {\n validateRuntimeDescriptorUrl(cssUrl, `cssUrls[${index}]`);\n if (isAbsoluteRuntimeUrl(cssUrl)) return;\n if (!isWidgetPackageCssArtifactPath(cssUrl)) {\n throw new Error(\n `cssUrls[${index}] relative URL ${JSON.stringify(cssUrl)} must be a top-level CSS artifact filename matching [A-Za-z0-9._~-]+.css.`,\n );\n }\n if (generatedCssUrlSet.has(cssUrl)) return;\n\n throw new Error(\n `cssUrls[${index}] relative URL ${JSON.stringify(cssUrl)} must match a generated top-level CSS artifact. ` +\n \"Import the CSS from the widget package bundle or remove it from cssUrls.\",\n );\n });\n\n const cssUrls = Array.from(\n new Set([...(sourceCssUrls ?? []), ...(generatedCssUrls ?? [])]),\n );\n cssUrls.forEach((cssUrl, index) => {\n validateRuntimeDescriptorUrl(cssUrl, `cssUrls[${index}]`);\n });\n return cssUrls;\n}\n\nfunction isAbsoluteRuntimeUrl(value: string): boolean {\n return /^[a-zA-Z][a-zA-Z\\d+.-]*:/.test(value);\n}\n\nfunction normalizePropertySchema(\n value: Record<string, unknown> | undefined,\n widgetType: string,\n): Record<string, unknown> {\n return { ...(value ?? {}), widgetType };\n}\n\nfunction normalizeContainer(value: unknown): WidgetRuntimeContainer {\n if (\n value === \"inline\" ||\n value === \"block\" ||\n value === \"card\" ||\n value === \"fullscreen\"\n ) {\n return value;\n }\n\n return DEFAULT_WIDGET_CONTAINER;\n}\n\nfunction normalizeResizable(value: unknown): WidgetRuntimeResizable {\n if (typeof value === \"boolean\") return value;\n if (value === \"horizontal\" || value === \"vertical\" || value === \"both\") {\n return value;\n }\n if (!isRecord(value)) return false;\n\n const horizontal = value.horizontal === true;\n const vertical = value.vertical === true;\n\n if (horizontal && vertical) return \"both\";\n if (horizontal) return \"horizontal\";\n if (vertical) return \"vertical\";\n return false;\n}\n\nfunction resolvePackageKey(\n sourcePackage: SourceWidgetPackageMetadata,\n owner: WidgetPackageOwnerKind,\n): string {\n const packageStableId = readNonEmptyTrimmedString(\n sourcePackage.packageStableId,\n );\n if (packageStableId) {\n return prefixPackageStableIdWithNonOwnerScope(\n packageStableId,\n sourcePackage.scope,\n );\n }\n\n return stripOwnerScopeFromPackageId(\n sourcePackage.packageId,\n sourcePackage.scope,\n owner,\n );\n}\n\nfunction prefixPackageStableIdWithNonOwnerScope(\n packageStableId: string,\n sourceScope: string | undefined,\n): string {\n const sourceScopeText = readNonEmptyTrimmedString(sourceScope);\n if (!sourceScopeText || isWidgetPackageOwnerKind(sourceScopeText)) {\n return packageStableId;\n }\n\n const sourceScopePrefix = `${sourceScopeText}.`;\n if (packageStableId.startsWith(sourceScopePrefix)) return packageStableId;\n return `${sourceScopeText}.${packageStableId}`;\n}\n\nfunction stripOwnerScopeFromPackageId(\n packageId: string,\n sourceScope: string | undefined,\n owner: WidgetPackageOwnerKind,\n): string {\n const ownerPrefix = `${owner}.`;\n if (\n packageId.startsWith(ownerPrefix) &&\n packageId.length > ownerPrefix.length\n ) {\n return packageId.slice(ownerPrefix.length);\n }\n\n const sourceScopeText = readNonEmptyTrimmedString(sourceScope);\n if (\n isWidgetPackageOwnerKind(sourceScopeText) &&\n packageId.startsWith(`${sourceScopeText}.`) &&\n packageId.length > sourceScopeText.length + 1\n ) {\n return packageId.slice(sourceScopeText.length + 1);\n }\n\n return packageId;\n}\n\nfunction readNonEmptyTrimmedString(\n value: string | undefined,\n): string | undefined {\n const trimmed = value?.trim();\n return trimmed ? trimmed : undefined;\n}\n\nfunction isWidgetPackageOwnerKind(\n value: string | undefined,\n): value is WidgetPackageOwnerKind {\n return value === \"company\" || value === \"droplet\";\n}\n\nfunction isUrlSafeDottedIdentifier(value: string): boolean {\n return URL_SAFE_DOTTED_IDENTIFIER_PATTERN.test(value);\n}\n\nfunction isUrlSafeWidgetName(value: string): boolean {\n return URL_SAFE_WIDGET_NAME_PATTERN.test(value);\n}\n\nfunction isUrlSafeSemver(value: string): boolean {\n return SEMVER_URL_SAFE_PATTERN.test(value);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import { execa } from \"execa\";\nimport fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport { type Result, success, failure } from \"@fluid-app/fluid-cli\";\nimport {\n loadSourceWidgetPackages,\n resolvePortalWidgetSourceConfig,\n} from \"./widget-package-config.js\";\nimport {\n buildWidgetPackageDescriptor,\n getWidgetPackageDescriptorPackageId,\n validateSingleSourceWidgetPackage,\n type ValidatedWidgetPackageBuild,\n type WidgetPackageOwnerKind,\n} from \"./widget-package-validation.js\";\nimport {\n collectWidgetPackageArtifacts,\n createPublishManifestMetadata,\n isWidgetPackageCssArtifactPath,\n} from \"./widget-package-artifacts.js\";\n\nconst DEFAULT_PUBLISH_DIR = \".fluid/widget-dist\";\nconst DEFAULT_RUNTIME_VERSION = \"1\";\nconst TEMP_BUILD_DIR = \".fluid/widget-build\";\nconst TEMP_CLI_DIR = \".fluid/tmp\";\nconst PROJECT_VITE_CONFIG_CANDIDATES = [\n \"vite.config.ts\",\n \"vite.config.mts\",\n \"vite.config.js\",\n \"vite.config.mjs\",\n] as const;\nconst BLOCKED_FLUID_PROJECT_PLUGIN_NAMES = [\n \"fluid-manifest-plugin\",\n \"fluid-preview-plugin\",\n \"fluid-builder-preview\",\n \"fluid-builder-preview-standalone\",\n \"fluid-portal-dev\",\n \"fluid-backend-dev\",\n] as const;\nconst WIDGET_PACKAGE_QUEUE_GLOBAL = \"FluidWidgetPackageQueue\";\nconst require = createRequire(import.meta.url);\n\nexport interface BuildSharedWidgetPackageOptions {\n readonly projectDir: string;\n readonly publishDir?: string;\n readonly owner?: WidgetPackageOwnerKind;\n}\n\nexport interface SharedWidgetPackageBuildResult {\n readonly publishDir: string;\n readonly packageId: string;\n readonly version: string;\n readonly manifestPath: string;\n readonly publishManifestPath: string;\n readonly widgetScriptPath: string;\n}\n\nexport interface SharedWidgetPackageBuildError {\n readonly code:\n | \"CONFIG_LOAD_FAILED\"\n | \"VALIDATION_FAILED\"\n | \"INVALID_PUBLISH_DIR\"\n | \"WRITE_FAILED\";\n readonly message: string;\n readonly details?: string;\n}\n\nexport interface ValidateSharedWidgetPackagePublishDirOptions {\n readonly optionName?: string;\n}\n\nexport function validateSharedWidgetPackagePublishDir(\n projectDir: string,\n publishDir: string = DEFAULT_PUBLISH_DIR,\n options: ValidateSharedWidgetPackagePublishDirOptions = {},\n): void {\n const label = options.optionName ?? \"publishDir\";\n\n if (path.isAbsolute(publishDir)) {\n throw new Error(`${label} must be relative to the project directory.`);\n }\n\n const normalizedPublishDir = normalizePublishDirForValidation(publishDir);\n if (\n normalizedPublishDir === \".fluid\" ||\n !normalizedPublishDir.startsWith(\".fluid/\")\n ) {\n throw new Error(`${label} must be a relative path under .fluid/.`);\n }\n\n if (isPathWithinReservedDir(normalizedPublishDir, TEMP_BUILD_DIR)) {\n throw new Error(\n `${label} must not be ${TEMP_BUILD_DIR} because it is reserved for temporary builder output.`,\n );\n }\n\n if (isPathWithinReservedDir(normalizedPublishDir, TEMP_CLI_DIR)) {\n throw new Error(\n `${label} must not be ${TEMP_CLI_DIR} because it is reserved for Fluid CLI temporary files.`,\n );\n }\n\n const resolvedProjectDir = path.resolve(projectDir);\n const resolvedPublishDir = path.resolve(resolvedProjectDir, publishDir);\n const relative = path.relative(resolvedProjectDir, resolvedPublishDir);\n\n if (\n relative === \"\" ||\n relative.startsWith(\"..\") ||\n path.isAbsolute(relative)\n ) {\n throw new Error(`${label} must stay inside the project directory.`);\n }\n}\n\nexport async function buildSharedWidgetPackage(\n options: BuildSharedWidgetPackageOptions,\n): Promise<\n Result<SharedWidgetPackageBuildResult, SharedWidgetPackageBuildError>\n> {\n const publishDirInput = options.publishDir ?? DEFAULT_PUBLISH_DIR;\n try {\n await validateWidgetPackageOutputPaths(options.projectDir, publishDirInput);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n return failure({\n code: \"INVALID_PUBLISH_DIR\",\n message: \"Unsafe widget package publish directory\",\n details: error.message,\n });\n }\n\n const sourcePackageResult = await loadSourceWidgetPackages(\n options.projectDir,\n );\n if (!sourcePackageResult.success) {\n return failure({\n code: \"CONFIG_LOAD_FAILED\",\n message: sourcePackageResult.error.message,\n details: sourcePackageResult.error.details,\n });\n }\n\n const validation = validateSingleSourceWidgetPackage(\n sourcePackageResult.value,\n { owner: options.owner },\n );\n if (!validation.success || !validation.value) {\n return failure({\n code: \"VALIDATION_FAILED\",\n message: validation.errors.map((error) => error.message).join(\"\\n\"),\n });\n }\n\n try {\n await validateWidgetPackageOutputPaths(options.projectDir, publishDirInput);\n\n const publishDir = path.resolve(options.projectDir, publishDirInput);\n await fs.emptyDir(publishDir);\n\n const tempDir = path.resolve(options.projectDir, TEMP_BUILD_DIR);\n await fs.emptyDir(tempDir);\n try {\n await buildWidgetScriptBundle({\n projectDir: options.projectDir,\n tempDir,\n publishDir,\n validated: validation.value,\n });\n } finally {\n await fs.remove(tempDir).catch(() => {});\n }\n\n const cssUrls = await collectCssUrls(publishDir);\n const descriptor = buildWidgetPackageDescriptor(validation.value, {\n cssUrls,\n });\n const manifestContent = stableStringify(descriptor);\n const publishPackageId = descriptor.packageId;\n\n const manifestPath = path.join(publishDir, \"manifest.json\");\n const widgetScriptPath = path.join(publishDir, \"widget.js\");\n const publishManifestPath = path.join(publishDir, \"publish-manifest.json\");\n\n await fs.writeFile(manifestPath, manifestContent, \"utf-8\");\n\n const artifacts = await collectWidgetPackageArtifacts(publishDir);\n const publishManifest = createPublishManifestMetadata({\n packageId: publishPackageId,\n version: validation.value.version,\n cliVersion: readCliVersion(),\n runtimeVersion: DEFAULT_RUNTIME_VERSION,\n manifestContent,\n artifacts,\n });\n await fs.writeFile(\n publishManifestPath,\n stableStringify(publishManifest),\n \"utf-8\",\n );\n\n return success({\n publishDir,\n packageId: getWidgetPackageDescriptorPackageId(validation.value),\n version: validation.value.version,\n manifestPath,\n publishManifestPath,\n widgetScriptPath,\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n const isPublishDirValidationError =\n /^(publishDir|reserved temporary build directory) /.test(error.message);\n return failure({\n code: isPublishDirValidationError\n ? \"INVALID_PUBLISH_DIR\"\n : \"WRITE_FAILED\",\n message: isPublishDirValidationError\n ? \"Unsafe widget package publish directory\"\n : \"Failed to build shared widget package artifacts\",\n details: error.message,\n });\n }\n}\n\nexport function createWidgetPackageEntrySource(options: {\n readonly configImportPath: string;\n readonly validated: ValidatedWidgetPackageBuild;\n}): string {\n return `import * as widgetConfig from ${JSON.stringify(options.configImportPath)};\n\nconst SOURCE_PACKAGE_MARKER = \"__fluidSourceWidgetPackage\";\nconst descriptors = ${JSON.stringify(options.validated.widgets, null, 2)};\n\nfunction isSourceWidgetPackage(value) {\n return Boolean(value && typeof value === \"object\" && value[SOURCE_PACKAGE_MARKER] === true);\n}\n\nfunction collectSourceWidgetPackages(mod) {\n return [\n mod.widgetPackage,\n ...(Array.isArray(mod.widgetPackages) ? mod.widgetPackages : []),\n mod.default,\n ].filter(isSourceWidgetPackage);\n}\n\nconst sourcePackage = collectSourceWidgetPackages(widgetConfig)[0];\nif (!sourcePackage) {\n throw new Error(\"No Fluid source widget package found while loading widget package bundle.\");\n}\n\nconst componentsByName = new Map(\n sourcePackage.widgets.map((widget) => [widget.name, widget.component]),\n);\n\nconst widgets = descriptors.map((descriptor) => {\n const component = componentsByName.get(descriptor.name);\n if (typeof component !== \"function\" && typeof component !== \"object\") {\n throw new Error(\"Widget package is missing component for \" + descriptor.name + \".\");\n }\n return { ...descriptor, component };\n});\n\nvar _fluidWidgets = globalObject.FluidWidgets;\nif (!_fluidWidgets || typeof _fluidWidgets.registerPackage !== \"function\") {\n throw new Error(\"FluidWidgets registry is not installed.\");\n}\n\n_fluidWidgets.registerPackage({\n packageId: ${JSON.stringify(options.validated.packageId)},\n version: ${JSON.stringify(options.validated.version)},\n widgets,\n});\n`;\n}\n\nasync function buildWidgetScriptBundle(options: {\n readonly projectDir: string;\n readonly tempDir: string;\n readonly publishDir: string;\n readonly validated: ValidatedWidgetPackageBuild;\n}): Promise<void> {\n const sourceConfig = await resolvePortalWidgetSourceConfig(\n options.projectDir,\n );\n if (!sourceConfig) {\n throw new Error(\"No portal widget source config found.\");\n }\n\n const entryPath = path.join(options.tempDir, \"widget-entry.ts\");\n const viteConfigPath = path.join(options.tempDir, \"vite.config.mjs\");\n await fs.writeFile(\n entryPath,\n createWidgetPackageEntrySource({\n configImportPath: pathToFileURL(sourceConfig.path).href,\n validated: options.validated,\n }),\n \"utf-8\",\n );\n await fs.writeFile(\n viteConfigPath,\n createViteConfigSource({\n entryPath,\n publishDir: options.publishDir,\n projectConfigPath: await resolveProjectViteConfigPath(options.projectDir),\n }),\n \"utf-8\",\n );\n\n const viteCliPath = resolveViteCliPath(options.projectDir);\n await execa(\n process.execPath,\n [viteCliPath, \"build\", \"--config\", viteConfigPath],\n {\n cwd: options.projectDir,\n stdio: \"pipe\",\n env: { ...process.env, NODE_ENV: \"production\" },\n },\n );\n\n const widgetScriptPath = path.join(options.publishDir, \"widget.js\");\n const widgetScriptContent = await fs.readFile(widgetScriptPath, \"utf-8\");\n await fs.writeFile(\n widgetScriptPath,\n wrapWidgetPackageScript(widgetScriptContent),\n \"utf-8\",\n );\n}\n\nexport function wrapWidgetPackageScript(widgetScriptContent: string): string {\n return `;(function () {\n var globalObject = window;\n var runWidgetPackage = function fluidWidgetPackageFactory() {\n // Intentionally shadow Rollup's expected FluidShared global with the wrapper-scoped host globals.\n var FluidShared = globalObject.FluidShared;\n if (!FluidShared) {\n throw new Error(\"window.FluidShared is not installed.\");\n }\n${indentScript(widgetScriptContent, \" \")}\n };\n\n if (globalObject.FluidShared) {\n runWidgetPackage();\n return;\n }\n\n var queue = globalObject.${WIDGET_PACKAGE_QUEUE_GLOBAL};\n if (!Array.isArray(queue)) {\n queue = [];\n globalObject.${WIDGET_PACKAGE_QUEUE_GLOBAL} = queue;\n }\n queue.push(runWidgetPackage);\n})();\n`;\n}\n\nfunction indentScript(source: string, indent: string): string {\n return source\n .split(\"\\n\")\n .map((line) => (line.length > 0 ? `${indent}${line}` : line))\n .join(\"\\n\");\n}\n\nexport function resolveViteCliPath(projectDir: string): string {\n const projectRequire = createRequire(path.join(projectDir, \"package.json\"));\n const projectViteCliPath = resolveViteCliPathFromRequire(projectRequire);\n if (projectViteCliPath) return projectViteCliPath;\n\n const cliViteCliPath = resolveViteCliPathFromRequire(require);\n if (cliViteCliPath) return cliViteCliPath;\n\n throw new Error(\n \"Unable to resolve Vite for the portal project. Install the project dependencies and ensure vite is available before building widget packages.\",\n );\n}\n\nexport async function resolveProjectViteConfigPath(\n projectDir: string,\n): Promise<string | undefined> {\n for (const fileName of PROJECT_VITE_CONFIG_CANDIDATES) {\n const candidate = path.join(projectDir, fileName);\n if (await fs.pathExists(candidate)) return candidate;\n }\n\n return undefined;\n}\n\nexport function createViteConfigSource(options: {\n readonly entryPath: string;\n readonly publishDir: string;\n readonly projectConfigPath?: string;\n}): string {\n const widgetConfigSource = createWidgetViteConfigObjectSource({\n ...options,\n disableConfigFileLookup: !options.projectConfigPath,\n });\n\n if (!options.projectConfigPath) {\n return `import { defineConfig } from \"vite\";\n\nexport default defineConfig(${widgetConfigSource});\n`;\n }\n\n return `import { defineConfig, loadConfigFromFile, mergeConfig } from \"vite\";\n\nconst projectConfigPath = ${JSON.stringify(options.projectConfigPath)};\nconst widgetConfig = ${widgetConfigSource};\nconst blockedFluidPluginNames = new Set(${JSON.stringify(BLOCKED_FLUID_PROJECT_PLUGIN_NAMES)});\n\nfunction isAllowedProjectPlugin(plugin) {\n return !plugin || typeof plugin !== \"object\" || !blockedFluidPluginNames.has(plugin.name);\n}\n\nfunction sanitizeProjectPlugins(pluginOption) {\n if (!Array.isArray(pluginOption)) {\n return isAllowedProjectPlugin(pluginOption) ? pluginOption : [];\n }\n\n return pluginOption\n .map((plugin) => Array.isArray(plugin) ? sanitizeProjectPlugins(plugin) : plugin)\n .filter(isAllowedProjectPlugin);\n}\n\nfunction copyProjectConfigValue(source, target, key) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n target[key] = source[key];\n }\n}\n\nfunction sanitizeProjectConfig(config) {\n if (!config || typeof config !== \"object\") return {};\n\n const sanitized = {};\n if (Object.prototype.hasOwnProperty.call(config, \"plugins\")) {\n sanitized.plugins = sanitizeProjectPlugins(config.plugins);\n }\n copyProjectConfigValue(config, sanitized, \"resolve\");\n copyProjectConfigValue(config, sanitized, \"define\");\n copyProjectConfigValue(config, sanitized, \"css\");\n copyProjectConfigValue(config, sanitized, \"esbuild\");\n copyProjectConfigValue(config, sanitized, \"json\");\n copyProjectConfigValue(config, sanitized, \"assetsInclude\");\n copyProjectConfigValue(config, sanitized, \"envDir\");\n copyProjectConfigValue(config, sanitized, \"envPrefix\");\n return sanitized;\n}\n\nexport default defineConfig(async (configEnv) => {\n const projectConfig = await loadConfigFromFile(configEnv, projectConfigPath);\n const safeProjectConfig = sanitizeProjectConfig(projectConfig?.config ?? {});\n return mergeConfig(safeProjectConfig, widgetConfig);\n});\n`;\n}\n\nfunction createWidgetViteConfigObjectSource(options: {\n readonly entryPath: string;\n readonly publishDir: string;\n readonly disableConfigFileLookup: boolean;\n}): string {\n const configFileSource = options.disableConfigFileLookup\n ? \" configFile: false,\\n\"\n : \"\";\n\n return `(() => {\n function createFluidWidgetBuildInvariants() {\n return {\n copyPublicDir: false,\n emptyOutDir: false,\n outDir: ${JSON.stringify(options.publishDir)},\n sourcemap: false,\n lib: {\n entry: ${JSON.stringify(options.entryPath)},\n formats: [\"iife\"],\n name: \"FluidWidgetPackage\",\n fileName: () => \"widget.js\",\n },\n rollupOptions: {\n external: [\"react\", \"react-dom\", \"react/jsx-runtime\"],\n output: {\n globals: {\n react: \"FluidShared.React\",\n \"react-dom\": \"FluidShared.ReactDOM\",\n \"react/jsx-runtime\": \"FluidShared.ReactJsxRuntime\",\n },\n },\n },\n };\n }\n\n function fluidWidgetBuildInvariantsPlugin() {\n return {\n name: \"fluid-widget-build-invariants\",\n enforce: \"post\",\n config() {\n return { build: createFluidWidgetBuildInvariants() };\n },\n configResolved(config) {\n Object.assign(config.build, createFluidWidgetBuildInvariants());\n },\n };\n }\n\n return {\n${configFileSource} publicDir: false,\n resolve: {\n conditions: [\"fluid-widget-authoring\"],\n },\n plugins: [fluidWidgetBuildInvariantsPlugin()],\n build: createFluidWidgetBuildInvariants(),\n };\n})()`;\n}\n\nasync function validateWidgetPackageOutputPaths(\n projectDir: string,\n publishDir: string,\n): Promise<void> {\n validateSharedWidgetPackagePublishDir(projectDir, publishDir);\n await rejectSymlinkedPathSegments({\n projectDir,\n relativePath: publishDir,\n label: \"publishDir\",\n });\n await rejectSymlinkedPathSegments({\n projectDir,\n relativePath: TEMP_BUILD_DIR,\n label: \"reserved temporary build directory\",\n });\n}\n\nasync function collectCssUrls(publishDir: string): Promise<string[]> {\n const entries = await fs.readdir(publishDir, { withFileTypes: true });\n return entries\n .filter(\n (entry) => entry.isFile() && isWidgetPackageCssArtifactPath(entry.name),\n )\n .map((entry) => entry.name)\n .sort();\n}\n\nasync function rejectSymlinkedPathSegments(options: {\n readonly projectDir: string;\n readonly relativePath: string;\n readonly label: string;\n}): Promise<void> {\n const resolvedProjectDir = path.resolve(options.projectDir);\n const resolvedTargetPath = path.resolve(\n resolvedProjectDir,\n options.relativePath,\n );\n const relative = path.relative(resolvedProjectDir, resolvedTargetPath);\n const segments = relative.split(path.sep).filter(Boolean);\n let currentPath = resolvedProjectDir;\n\n for (const segment of segments) {\n currentPath = path.join(currentPath, segment);\n let stat: fs.Stats;\n try {\n stat = await fs.lstat(currentPath);\n } catch (err) {\n if (isNodeError(err) && err.code === \"ENOENT\") return;\n throw err;\n }\n\n if (stat.isSymbolicLink()) {\n throw new Error(`${options.label} must not include symbolic links.`);\n }\n }\n}\n\nfunction normalizePublishDirForValidation(value: string): string {\n return toPosixPath(path.normalize(value)).replace(/\\/+$/, \"\") || \".\";\n}\n\nfunction isPathWithinReservedDir(value: string, reservedDir: string): boolean {\n return value === reservedDir || value.startsWith(`${reservedDir}/`);\n}\n\nfunction toPosixPath(value: string): string {\n return value.split(path.sep).join(\"/\");\n}\n\nfunction stableStringify(value: unknown): string {\n return `${JSON.stringify(value, null, 2)}\\n`;\n}\n\nfunction readCliVersion(): string {\n const startDir = path.dirname(fileURLToPath(import.meta.url));\n for (const packageJsonPath of candidatePackageJsonPaths(startDir)) {\n try {\n const packageJson = require(packageJsonPath) as {\n name?: unknown;\n version?: unknown;\n };\n if (\n packageJson.name === \"@fluid-app/fluid-cli-portal\" &&\n typeof packageJson.version === \"string\"\n ) {\n return packageJson.version;\n }\n } catch {\n // Keep walking upward until the package root is found.\n }\n }\n\n return \"0.0.0\";\n}\n\nfunction resolveViteCliPathFromRequire(\n moduleRequire: NodeJS.Require,\n): string | undefined {\n try {\n const packageJsonPath = moduleRequire.resolve(\"vite/package.json\");\n const packageJson = moduleRequire(packageJsonPath) as { bin?: unknown };\n const binPath = getViteBinPath(packageJson.bin);\n if (!binPath) return undefined;\n\n return path.resolve(path.dirname(packageJsonPath), binPath);\n } catch (err) {\n if (isModuleResolutionError(err)) return undefined;\n throw err;\n }\n}\n\nfunction getViteBinPath(bin: unknown): string | undefined {\n if (typeof bin === \"string\") return bin;\n if (!isRecord(bin)) return undefined;\n\n const viteBin = bin.vite;\n return typeof viteBin === \"string\" ? viteBin : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isNodeError(value: unknown): value is NodeJS.ErrnoException {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"code\" in value &&\n typeof value.code === \"string\"\n );\n}\n\nfunction isModuleResolutionError(value: unknown): boolean {\n return (\n isNodeError(value) &&\n (value.code === \"MODULE_NOT_FOUND\" || value.code === \"ERR_MODULE_NOT_FOUND\")\n );\n}\n\nfunction candidatePackageJsonPaths(startDir: string): string[] {\n const paths: string[] = [];\n let current = startDir;\n\n while (true) {\n paths.push(path.join(current, \"package.json\"));\n const parent = path.dirname(current);\n if (parent === current) return paths;\n current = parent;\n }\n}\n","/**\n * Shared widget package publish/upload helpers.\n *\n * These utilities cover the two owner scopes currently supported by the\n * portal widget package upload API: marketplace droplets and company-owned\n * Fluid OS packages. They intentionally do not register CLI commands; command\n * implementations can compose the typed payload builders, session/complete\n * requests, signed URL uploads, and dry-run orchestration exposed here.\n */\n\nimport type { FetchClient } from \"@fluid-app/fluid-cli\";\nimport { fluidOs } from \"@fluid-app/fluidos-api-client\";\nimport type { ArtifactMetadata } from \"./widget-package-artifacts.js\";\n\nexport type WidgetPackageUploadOwner =\n | { readonly kind: \"droplet\"; readonly uuid: string }\n | { readonly kind: \"company\" };\n\nexport type WidgetPackageArtifactMetadata = ArtifactMetadata;\n\nexport interface WidgetPackageUploadArtifact extends WidgetPackageArtifactMetadata {\n readonly body: BodyInit;\n}\n\nexport interface WidgetPackageSessionRequest {\n readonly version: string;\n readonly packageKey: string;\n readonly builderVersion: string;\n readonly cliVersion: string;\n readonly runtimeVersion: string;\n readonly manifestHash: string;\n readonly manifest: Record<string, unknown>;\n readonly artifacts: readonly WidgetPackageArtifactMetadata[];\n}\n\nexport interface WidgetPackagePublishRequest extends Omit<\n WidgetPackageSessionRequest,\n \"artifacts\"\n> {\n readonly artifacts: readonly WidgetPackageUploadArtifact[];\n}\n\nexport type WidgetPackageArtifactPayload = ArtifactMetadata;\n\nexport interface WidgetPackageUploadSessionPayload {\n readonly version: string;\n readonly package_key: string;\n readonly builder_version: string;\n readonly cli_version: string;\n readonly runtime_version: string;\n readonly manifest_hash: string;\n readonly manifest: Record<string, unknown>;\n readonly artifacts: readonly WidgetPackageArtifactPayload[];\n}\n\nexport interface WidgetPackageCompleteUploadPayload {\n readonly package_key: string;\n readonly artifacts: readonly WidgetPackageArtifactPayload[];\n}\n\nexport interface WidgetPackageSignedUpload {\n readonly path: string;\n readonly url: string;\n readonly contentType: string;\n readonly headers: Readonly<Record<string, string>>;\n}\n\nexport interface WidgetPackageUploadSession {\n readonly version: string;\n readonly uploads: readonly WidgetPackageSignedUpload[];\n readonly raw: unknown;\n}\n\nexport interface WidgetPackageArtifactUploadResult {\n readonly path: string;\n readonly status: number;\n readonly contentType: string;\n}\n\nexport interface WidgetPackageCompleteResult {\n readonly version: string;\n readonly status?: string;\n readonly packageKey?: string;\n readonly raw: unknown;\n}\n\nexport interface WidgetPackagePublishResult {\n readonly dryRun: boolean;\n readonly sessionPayload: WidgetPackageUploadSessionPayload;\n readonly session?: WidgetPackageUploadSession;\n readonly uploadedArtifacts?: readonly WidgetPackageArtifactUploadResult[];\n readonly complete?: WidgetPackageCompleteResult;\n}\n\ninterface BasePublishWidgetPackageVersionOptions {\n readonly owner: WidgetPackageUploadOwner;\n readonly request: WidgetPackagePublishRequest;\n readonly fetchImpl?: WidgetPackageUploadFetch;\n}\n\nexport interface DryRunPublishWidgetPackageVersionOptions extends BasePublishWidgetPackageVersionOptions {\n readonly client?: FetchClient;\n readonly dryRun: true;\n}\n\nexport interface PublishWidgetPackageVersionUploadOptions extends BasePublishWidgetPackageVersionOptions {\n readonly client: FetchClient;\n readonly dryRun?: boolean;\n}\n\nexport type PublishWidgetPackageVersionOptions =\n | DryRunPublishWidgetPackageVersionOptions\n | PublishWidgetPackageVersionUploadOptions;\n\ntype FluidOsCreateWidgetPackageVersionPayload = Parameters<\n typeof fluidOs.fluid_os_v0_create_widget_package_version\n>[1];\n\ntype FluidOsCompleteWidgetPackageVersionUploadPayload = NonNullable<\n Parameters<\n typeof fluidOs.fluid_os_v0_complete_widget_package_version_upload\n >[2]\n>;\n\nexport type WidgetPackageUploadFetch = (\n input: string | URL,\n init: RequestInit,\n) => Promise<Response>;\n\nexport class WidgetPackageUploadError extends Error {\n public readonly code: string;\n\n constructor(code: string, message: string) {\n super(message);\n this.name = \"WidgetPackageUploadError\";\n this.code = code;\n }\n}\n\nconst SESSION_ARRAY_KEYS = [\n \"uploads\",\n \"artifacts\",\n \"signedUploads\",\n \"signed_uploads\",\n \"signedUrls\",\n \"signed_urls\",\n \"uploadUrls\",\n \"upload_urls\",\n] as const;\n\nconst SESSION_RECORD_KEYS = [\n \"signedUrls\",\n \"signed_urls\",\n \"uploadUrls\",\n \"upload_urls\",\n] as const;\n\nexport function buildWidgetPackageArtifactPayload(\n artifact: WidgetPackageArtifactMetadata,\n): WidgetPackageArtifactPayload {\n return {\n path: artifact.path,\n sha256: artifact.sha256,\n bytes: artifact.bytes,\n contentType: artifact.contentType,\n };\n}\n\nexport function buildWidgetPackageUploadSessionPayload(\n request: WidgetPackageSessionRequest,\n): WidgetPackageUploadSessionPayload {\n return {\n version: request.version,\n package_key: request.packageKey,\n builder_version: request.builderVersion,\n cli_version: request.cliVersion,\n runtime_version: request.runtimeVersion,\n manifest_hash: request.manifestHash,\n manifest: request.manifest,\n artifacts: request.artifacts.map(buildWidgetPackageArtifactPayload),\n };\n}\n\nexport function buildWidgetPackageCompleteUploadPayload(\n packageKey: string,\n artifacts: readonly WidgetPackageArtifactMetadata[],\n): WidgetPackageCompleteUploadPayload {\n return {\n package_key: packageKey,\n artifacts: artifacts.map(buildWidgetPackageArtifactPayload),\n };\n}\n\nexport function getWidgetPackageUploadSessionRoute(\n owner: WidgetPackageUploadOwner,\n): string {\n switch (owner.kind) {\n case \"droplet\":\n return `/api/droplets/${encodeURIComponent(owner.uuid)}/widget_package_versions`;\n case \"company\":\n return \"/api/company/fluid_os/widget_package_versions\";\n }\n}\n\nexport function getWidgetPackageCompleteUploadRoute(\n owner: WidgetPackageUploadOwner,\n version: string,\n): string {\n switch (owner.kind) {\n case \"droplet\":\n return `/api/droplets/${encodeURIComponent(owner.uuid)}/widget_package_versions/${encodeURIComponent(version)}/complete_upload`;\n case \"company\":\n return `/api/company/fluid_os/widget_package_versions/${encodeURIComponent(version)}/complete_upload`;\n }\n}\n\nexport async function requestWidgetPackageUploadSession(\n client: FetchClient,\n owner: WidgetPackageUploadOwner,\n request: WidgetPackageSessionRequest,\n): Promise<WidgetPackageUploadSession> {\n const payload = buildWidgetPackageUploadSessionPayload(request);\n\n try {\n const response =\n owner.kind === \"company\"\n ? await fluidOs.fluid_os_v0_create_widget_package_version(\n client,\n payload as FluidOsCreateWidgetPackageVersionPayload,\n )\n : await client.post<unknown>(\n getWidgetPackageUploadSessionRoute(owner),\n payload,\n );\n return normalizeWidgetPackageUploadSession(\n response,\n request.version,\n request.artifacts,\n );\n } catch (err) {\n if (err instanceof WidgetPackageUploadError) {\n throw err;\n }\n\n throw new WidgetPackageUploadError(\n \"SESSION_REQUEST_FAILED\",\n `Failed to create widget package upload session: ${formatUnknownError(err)}`,\n );\n }\n}\n\nexport async function uploadWidgetPackageArtifacts(\n session: WidgetPackageUploadSession,\n artifacts: readonly WidgetPackageUploadArtifact[],\n fetchImpl: WidgetPackageUploadFetch = fetch,\n): Promise<WidgetPackageArtifactUploadResult[]> {\n const uploadsByPath = new Map(\n session.uploads.map((upload) => [upload.path, upload] as const),\n );\n const results: WidgetPackageArtifactUploadResult[] = [];\n\n for (const artifact of artifacts) {\n const upload = uploadsByPath.get(artifact.path);\n if (!upload) {\n throw new WidgetPackageUploadError(\n \"MISSING_SIGNED_URL\",\n `Upload session did not include a signed URL for artifact \"${artifact.path}\".`,\n );\n }\n\n if (upload.contentType !== artifact.contentType) {\n throw new WidgetPackageUploadError(\n \"CONTENT_TYPE_MISMATCH\",\n `Upload session expected artifact \"${artifact.path}\" to use content type \"${upload.contentType}\", but local artifact uses \"${artifact.contentType}\".`,\n );\n }\n\n let response: Response;\n try {\n response = await fetchImpl(upload.url, {\n method: \"PUT\",\n headers: mergeUploadHeaders(upload.headers, upload.contentType),\n body: artifact.body,\n });\n } catch (err) {\n throw new WidgetPackageUploadError(\n \"ARTIFACT_UPLOAD_FAILED\",\n `Failed to upload artifact \"${artifact.path}\": ${formatUnknownError(err)}`,\n );\n }\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n const details = body.trim() ? `: ${body.trim().slice(0, 500)}` : \"\";\n throw new WidgetPackageUploadError(\n \"ARTIFACT_UPLOAD_FAILED\",\n `Failed to upload artifact \"${artifact.path}\": PUT returned HTTP ${response.status}${details}`,\n );\n }\n\n results.push({\n path: artifact.path,\n status: response.status,\n contentType: upload.contentType,\n });\n }\n\n return results;\n}\n\nexport async function completeWidgetPackageUpload(\n client: FetchClient,\n owner: WidgetPackageUploadOwner,\n version: string,\n packageKey: string,\n artifacts: readonly WidgetPackageArtifactMetadata[],\n): Promise<WidgetPackageCompleteResult> {\n const payload = buildWidgetPackageCompleteUploadPayload(\n packageKey,\n artifacts,\n );\n\n try {\n const response =\n owner.kind === \"company\"\n ? await fluidOs.fluid_os_v0_complete_widget_package_version_upload(\n client,\n version,\n payload as FluidOsCompleteWidgetPackageVersionUploadPayload,\n )\n : await client.post<unknown>(\n getWidgetPackageCompleteUploadRoute(owner, version),\n payload,\n );\n return normalizeWidgetPackageCompleteResponse(response, version);\n } catch (err) {\n if (err instanceof WidgetPackageUploadError) {\n throw err;\n }\n\n throw new WidgetPackageUploadError(\n \"COMPLETE_UPLOAD_FAILED\",\n `Failed to complete widget package upload: ${formatUnknownError(err)}`,\n );\n }\n}\n\nexport async function publishWidgetPackageVersion(\n options: PublishWidgetPackageVersionOptions,\n): Promise<WidgetPackagePublishResult> {\n const sessionPayload = buildWidgetPackageUploadSessionPayload(\n options.request,\n );\n\n if (options.dryRun) {\n return { dryRun: true, sessionPayload };\n }\n\n if (!options.client) {\n throw new Error(\"A FetchClient is required when dryRun is false.\");\n }\n\n const session = await requestWidgetPackageUploadSession(\n options.client,\n options.owner,\n options.request,\n );\n const uploadedArtifacts = await uploadWidgetPackageArtifacts(\n session,\n options.request.artifacts,\n options.fetchImpl,\n );\n const complete = await completeWidgetPackageUpload(\n options.client,\n options.owner,\n session.version,\n options.request.packageKey,\n options.request.artifacts,\n );\n\n return {\n dryRun: false,\n sessionPayload,\n session,\n uploadedArtifacts,\n complete,\n };\n}\n\nexport function normalizeWidgetPackageUploadSession(\n response: unknown,\n requestedVersion: string,\n requestedArtifacts: readonly WidgetPackageArtifactMetadata[],\n): WidgetPackageUploadSession {\n const record = requireRecord(\n response,\n \"Upload session response must be a JSON object.\",\n );\n const responseVersion = getResponseVersion(record);\n\n if (responseVersion && responseVersion !== requestedVersion) {\n throw new WidgetPackageUploadError(\n \"INVALID_SESSION_RESPONSE\",\n `Upload session response version \"${responseVersion}\" did not match requested version \"${requestedVersion}\".`,\n );\n }\n\n const version = responseVersion ?? requestedVersion;\n const nestedRecord = getNestedVersionRecord(record);\n const uploadRecords = nestedRecord ? [record, nestedRecord] : [record];\n const uploads = getSignedUploads(uploadRecords, requestedArtifacts);\n const missingUploadPaths = requestedArtifacts\n .map((artifact) => artifact.path)\n .filter(\n (artifactPath) => !uploads.some((upload) => upload.path === artifactPath),\n );\n\n if (missingUploadPaths.length > 0) {\n throw new WidgetPackageUploadError(\n \"INVALID_SESSION_RESPONSE\",\n `Upload session response is missing signed URLs for artifact(s): ${missingUploadPaths.join(\", \")}.`,\n );\n }\n\n return { version, uploads, raw: response };\n}\n\nexport function normalizeWidgetPackageCompleteResponse(\n response: unknown,\n requestedVersion: string,\n): WidgetPackageCompleteResult {\n if (response == null) {\n return { version: requestedVersion, raw: response };\n }\n\n const record = requireRecord(\n response,\n \"Complete upload response must be a JSON object or empty response.\",\n );\n const nested = getNestedVersionRecord(record) ?? record;\n const responseVersion = getResponseVersion(nested);\n\n if (responseVersion && responseVersion !== requestedVersion) {\n throw new WidgetPackageUploadError(\n \"INVALID_COMPLETE_RESPONSE\",\n `Complete upload response version \"${responseVersion}\" did not match requested version \"${requestedVersion}\".`,\n );\n }\n\n const packageKey =\n getStringProperty(nested, \"package_key\") ??\n getStringProperty(nested, \"packageKey\") ??\n getStringProperty(nested, \"packageId\");\n const status =\n getStringProperty(nested, \"status\") ?? getStringProperty(nested, \"state\");\n\n return {\n version: responseVersion ?? requestedVersion,\n ...(status ? { status } : {}),\n ...(packageKey ? { packageKey } : {}),\n raw: response,\n };\n}\n\nfunction getSignedUploads(\n records: readonly Record<string, unknown>[],\n requestedArtifacts: readonly WidgetPackageArtifactMetadata[],\n): WidgetPackageSignedUpload[] {\n const uploads: WidgetPackageSignedUpload[] = [];\n\n for (const record of records) {\n for (const key of SESSION_ARRAY_KEYS) {\n const value = record[key];\n if (!Array.isArray(value)) continue;\n\n for (const item of value) {\n const upload = signedUploadFromRecord(item, requestedArtifacts);\n if (upload) uploads.push(upload);\n }\n }\n\n for (const key of SESSION_RECORD_KEYS) {\n const value = record[key];\n if (!isRecord(value) || Array.isArray(value)) continue;\n\n for (const [artifactPath, uploadValue] of Object.entries(value)) {\n const upload = signedUploadFromKeyedValue(\n artifactPath,\n uploadValue,\n requestedArtifacts,\n );\n if (upload) uploads.push(upload);\n }\n }\n }\n\n return dedupeUploads(uploads);\n}\n\nfunction signedUploadFromRecord(\n value: unknown,\n requestedArtifacts: readonly WidgetPackageArtifactMetadata[],\n): WidgetPackageSignedUpload | null {\n if (!isRecord(value)) return null;\n\n const artifactPath = readFirstString(value, [\n \"path\",\n \"key\",\n \"artifactPath\",\n \"artifact_path\",\n \"artifactKey\",\n \"artifact_key\",\n \"name\",\n ]);\n const url = readFirstString(value, [\n \"url\",\n \"signedUrl\",\n \"signed_url\",\n \"uploadUrl\",\n \"upload_url\",\n ]);\n if (!artifactPath || !url) return null;\n\n const requestedArtifact = findRequestedArtifact(\n requestedArtifacts,\n artifactPath,\n );\n const contentType =\n readFirstString(value, [\n \"contentType\",\n \"content_type\",\n \"expectedContentType\",\n \"expected_content_type\",\n ]) ?? requestedArtifact?.contentType;\n\n if (!contentType) return null;\n\n return {\n path: artifactPath,\n url,\n contentType,\n headers: getHeaders(value[\"headers\"]),\n };\n}\n\nfunction signedUploadFromKeyedValue(\n artifactPath: string,\n value: unknown,\n requestedArtifacts: readonly WidgetPackageArtifactMetadata[],\n): WidgetPackageSignedUpload | null {\n const requestedArtifact = findRequestedArtifact(\n requestedArtifacts,\n artifactPath,\n );\n\n if (typeof value === \"string\") {\n if (!requestedArtifact) return null;\n return {\n path: artifactPath,\n url: value,\n contentType: requestedArtifact.contentType,\n headers: {},\n };\n }\n\n if (!isRecord(value)) return null;\n\n const url = readFirstString(value, [\n \"url\",\n \"signedUrl\",\n \"signed_url\",\n \"uploadUrl\",\n \"upload_url\",\n ]);\n if (!url) return null;\n\n const contentType =\n readFirstString(value, [\n \"contentType\",\n \"content_type\",\n \"expectedContentType\",\n \"expected_content_type\",\n ]) ?? requestedArtifact?.contentType;\n\n if (!contentType) return null;\n\n return {\n path: artifactPath,\n url,\n contentType,\n headers: getHeaders(value[\"headers\"]),\n };\n}\n\nfunction normalizeHeaderName(name: string): string {\n return name.toLowerCase();\n}\n\nfunction mergeUploadHeaders(\n headers: Readonly<Record<string, string>>,\n contentType: string,\n): Record<string, string> {\n const merged: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(headers)) {\n if (normalizeHeaderName(key) === \"content-type\") continue;\n merged[key] = value;\n }\n\n merged[\"Content-Type\"] = contentType;\n return merged;\n}\n\nfunction dedupeUploads(\n uploads: readonly WidgetPackageSignedUpload[],\n): WidgetPackageSignedUpload[] {\n const deduped = new Map<string, WidgetPackageSignedUpload>();\n for (const upload of uploads) {\n deduped.set(upload.path, upload);\n }\n return Array.from(deduped.values());\n}\n\nfunction findRequestedArtifact(\n requestedArtifacts: readonly WidgetPackageArtifactMetadata[],\n artifactPath: string,\n): WidgetPackageArtifactMetadata | undefined {\n return requestedArtifacts.find((artifact) => artifact.path === artifactPath);\n}\n\nfunction requireRecord(\n value: unknown,\n message: string,\n): Record<string, unknown> {\n if (!isRecord(value) || Array.isArray(value)) {\n throw new WidgetPackageUploadError(\"INVALID_RESPONSE\", message);\n }\n return value;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction getStringProperty(\n record: Record<string, unknown>,\n key: string,\n): string | undefined {\n const value = record[key];\n if (typeof value === \"string\" && value.trim().length > 0) {\n return value;\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value);\n }\n return undefined;\n}\n\nfunction readFirstString(\n record: Record<string, unknown>,\n keys: readonly string[],\n): string | undefined {\n for (const key of keys) {\n const value = getStringProperty(record, key);\n if (value) return value;\n }\n return undefined;\n}\n\nfunction getHeaders(value: unknown): Record<string, string> {\n if (!isRecord(value) || Array.isArray(value)) return {};\n\n const headers: Record<string, string> = {};\n for (const [key, headerValue] of Object.entries(value)) {\n if (typeof headerValue === \"string\") {\n headers[key] = headerValue;\n }\n }\n return headers;\n}\n\nfunction getResponseVersion(\n record: Record<string, unknown>,\n): string | undefined {\n const directVersion = getStringProperty(record, \"version\");\n if (directVersion) return directVersion;\n\n const nested = getNestedVersionRecord(record);\n return nested ? getStringProperty(nested, \"version\") : undefined;\n}\n\nfunction getNestedVersionRecord(\n record: Record<string, unknown>,\n): Record<string, unknown> | undefined {\n const candidates = [\n record[\"portal_widget_package_version\"],\n record[\"widget_package_version\"],\n record[\"package_version\"],\n ];\n\n for (const candidate of candidates) {\n if (isRecord(candidate) && !Array.isArray(candidate)) {\n return candidate;\n }\n }\n\n return undefined;\n}\n\nfunction formatUnknownError(err: unknown): string {\n const base = err instanceof Error ? err.message : String(err);\n\n if (isRecord(err) && \"data\" in err) {\n return `${base} — ${JSON.stringify(err.data)}`;\n }\n\n return base;\n}\n","import { findProjectConfig, readConfig } from \"@fluid-app/fluid-cli\";\nimport type { FetchClient } from \"@fluid-app/fluid-cli\";\nimport { createFetchClient } from \"@fluid-app/fluidos-api-client\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport path from \"node:path\";\nimport {\n buildSharedWidgetPackage,\n validateSharedWidgetPackagePublishDir,\n} from \"../utils/widget-package-builder.js\";\nimport type {\n BuildSharedWidgetPackageOptions,\n SharedWidgetPackageBuildResult,\n} from \"../utils/widget-package-builder.js\";\nimport { publishWidgetPackageVersion } from \"../utils/widget-package-upload.js\";\nimport type {\n WidgetPackagePublishRequest,\n WidgetPackagePublishResult,\n WidgetPackageUploadOwner,\n} from \"../utils/widget-package-upload.js\";\nimport {\n collectWidgetPackageArtifacts,\n computeArtifactMetadata,\n sha256,\n type ArtifactMetadata,\n type PublishManifestMetadata,\n} from \"../utils/widget-package-artifacts.js\";\nimport type { WidgetPackageOwnerKind as WidgetPackageBuildOwner } from \"../utils/widget-package-validation.js\";\n\nexport interface PublishWidgetRuntimeArtifactsOptions {\n readonly projectDir: string;\n readonly outDir: string;\n readonly buildOwner: WidgetPackageBuildOwner;\n readonly uploadOwner: WidgetPackageUploadOwner;\n readonly dryRun?: boolean;\n readonly client?: FetchClient;\n}\n\nexport interface PublishWidgetRuntimeArtifactsResult {\n readonly build: SharedWidgetPackageBuildResult;\n readonly request: WidgetPackagePublishRequest;\n readonly publish: WidgetPackagePublishResult;\n}\n\nexport interface PublishWidgetRuntimeArtifactsDependencies {\n readonly buildSharedWidgetPackage?: typeof buildSharedWidgetPackage;\n readonly publishWidgetPackageVersion?: typeof publishWidgetPackageVersion;\n}\n\nexport async function publishWidgetRuntimeArtifacts(\n options: PublishWidgetRuntimeArtifactsOptions,\n dependencies: PublishWidgetRuntimeArtifactsDependencies = {},\n): Promise<PublishWidgetRuntimeArtifactsResult> {\n const buildPackage =\n dependencies.buildSharedWidgetPackage ?? buildSharedWidgetPackage;\n const publishVersion =\n dependencies.publishWidgetPackageVersion ?? publishWidgetPackageVersion;\n\n const isDryRun = options.dryRun === true;\n const client = options.client;\n\n if (!isDryRun && !client) {\n throw new Error(\"A FetchClient is required when dryRun is false.\");\n }\n\n const safeOutDir = validateWidgetPublishOutDir(\n options.projectDir,\n options.outDir,\n );\n const buildResult = await buildPackage({\n projectDir: options.projectDir,\n publishDir: safeOutDir,\n owner: options.buildOwner,\n } satisfies BuildSharedWidgetPackageOptions);\n\n if (!buildResult.success) {\n const details = buildResult.error.details\n ? `\\n${buildResult.error.details}`\n : \"\";\n throw new Error(`${buildResult.error.message}${details}`);\n }\n\n const request = await createWidgetPackagePublishRequest({\n publishDir: buildResult.value.publishDir,\n manifestPath: buildResult.value.manifestPath,\n publishManifestPath: buildResult.value.publishManifestPath,\n owner: options.buildOwner,\n });\n\n let publish: WidgetPackagePublishResult;\n if (isDryRun) {\n publish = await publishVersion({\n owner: options.uploadOwner,\n request,\n dryRun: true,\n });\n } else {\n if (!client) {\n throw new Error(\"A FetchClient is required when dryRun is false.\");\n }\n\n publish = await publishVersion({\n client,\n owner: options.uploadOwner,\n request,\n });\n }\n\n return { build: buildResult.value, request, publish };\n}\n\nexport async function createWidgetPackagePublishRequest(options: {\n readonly publishDir: string;\n readonly manifestPath: string;\n readonly publishManifestPath: string;\n readonly owner: WidgetPackageBuildOwner;\n}): Promise<WidgetPackagePublishRequest> {\n const manifestContent = await fs.readFile(options.manifestPath);\n const manifest = parseJsonRecord(\n manifestContent.toString(\"utf-8\"),\n options.manifestPath,\n );\n const publishManifest = await readPublishManifest(\n options.publishManifestPath,\n );\n assertManifestIdentityMatches(\n manifest,\n publishManifest,\n options.manifestPath,\n );\n assertMetadataMatches({\n label: \"manifestHash\",\n path: \"manifest.json\",\n expected: publishManifest.manifestHash,\n actual: sha256(manifestContent),\n });\n const collectedArtifacts = await collectWidgetPackageArtifacts(\n options.publishDir,\n );\n assertArtifactInventoryMatches(publishManifest.artifacts, collectedArtifacts);\n const artifacts = await readUploadArtifacts(\n options.publishDir,\n publishManifest.artifacts,\n );\n\n return {\n version: publishManifest.version,\n packageKey: stripOwnerPrefix(publishManifest.packageId, options.owner),\n builderVersion: publishManifest.builderVersion,\n cliVersion: publishManifest.cliVersion,\n runtimeVersion: publishManifest.runtimeVersion,\n manifestHash: publishManifest.manifestHash,\n manifest,\n artifacts,\n };\n}\n\nexport function createAuthenticatedWidgetPackageClient(): FetchClient {\n const { profile, profileName, token } = resolveAuthenticatedProfile();\n if (!token) {\n if (!profileName) {\n throw new Error(\n \"Not logged in. Run \" + chalk.cyan(\"fluid login\") + \" first.\",\n );\n }\n throw new Error(\n \"No auth token found for profile \" +\n chalk.cyan(profileName) +\n \". Run \" +\n chalk.cyan(\"fluid login\") +\n \" to re-authenticate.\",\n );\n }\n\n return createFetchClient({\n baseUrl:\n profile?.baseUrl ??\n process.env[\"FLUID_API_BASE\"] ??\n \"https://api.fluid.app\",\n getAuthToken: () => token,\n });\n}\n\ntype ProfileWithBaseUrl = ReturnType<typeof readConfig>[\"profiles\"][string] & {\n readonly baseUrl?: string;\n};\n\nfunction resolveAuthenticatedProfile(): {\n readonly profile?: ProfileWithBaseUrl;\n readonly profileName?: string;\n readonly token?: string;\n} {\n const config = readConfig();\n const projectConfig = findProjectConfig(process.cwd());\n\n if (projectConfig?.profile) {\n const profile = config.profiles[projectConfig.profile] as\n | ProfileWithBaseUrl\n | undefined;\n if (profile) {\n return {\n profile,\n profileName: projectConfig.profile,\n token: profile.token,\n };\n }\n }\n\n if (!config.activeProfile) return {};\n const profile = config.profiles[config.activeProfile] as\n | ProfileWithBaseUrl\n | undefined;\n if (!profile) return {};\n\n return {\n profile,\n profileName: config.activeProfile,\n token: profile.token,\n };\n}\n\nexport function printWidgetPublishSummary(options: {\n readonly title: string;\n readonly ownerLabel: string;\n readonly environment?: string;\n readonly outDir: string;\n readonly result: PublishWidgetRuntimeArtifactsResult;\n}): void {\n console.log();\n console.log(chalk.green.bold(`${options.title} complete`));\n console.log();\n console.log(chalk.gray(\"Owner: \") + chalk.white(options.ownerLabel));\n if (options.environment) {\n console.log(chalk.gray(\"Environment: \") + chalk.white(options.environment));\n }\n console.log(\n chalk.gray(\"Package: \") + chalk.white(options.result.build.packageId),\n );\n console.log(\n chalk.gray(\"Version: \") + chalk.white(options.result.build.version),\n );\n console.log(chalk.gray(\"Output: \") + chalk.cyan(options.outDir));\n console.log(\n chalk.gray(\"Artifacts: \") +\n chalk.white(String(options.result.request.artifacts.length)),\n );\n console.log();\n}\n\nexport function printRuntimeOnlyNotice(): void {\n console.log(\n chalk.yellow(\n \"This publishes widget runtime artifacts only; it does not deploy the hosted portal shell.\",\n ),\n );\n console.log();\n}\n\nexport function printDryRunSessionPayload(\n result: PublishWidgetRuntimeArtifactsResult,\n): void {\n console.log(chalk.bold(\"Dry-run upload session payload:\"));\n console.log(JSON.stringify(result.publish.sessionPayload, null, 2));\n console.log();\n}\n\nexport function validateWidgetPublishOutDir(\n projectDir: string,\n outDir: string,\n): string {\n validateSharedWidgetPackagePublishDir(projectDir, outDir, {\n optionName: \"--out-dir\",\n });\n\n return outDir;\n}\n\nasync function readJsonRecord(\n filePath: string,\n): Promise<Record<string, unknown>> {\n return parseJsonRecord(await fs.readFile(filePath, \"utf-8\"), filePath);\n}\n\nfunction parseJsonRecord(\n content: string,\n filePath: string,\n): Record<string, unknown> {\n const value = JSON.parse(content) as unknown;\n if (!isRecord(value) || Array.isArray(value)) {\n throw new Error(`${path.basename(filePath)} must contain a JSON object.`);\n }\n return value;\n}\n\nasync function readPublishManifest(\n filePath: string,\n): Promise<PublishManifestMetadata> {\n const record = await readJsonRecord(filePath);\n const artifactsValue = record[\"artifacts\"];\n if (!Array.isArray(artifactsValue)) {\n throw new Error(\"publish-manifest.json must include an artifacts array.\");\n }\n\n return {\n packageId: readRequiredString(record, \"packageId\", filePath),\n version: readRequiredString(record, \"version\", filePath),\n builderVersion: readRequiredString(record, \"builderVersion\", filePath),\n cliVersion: readRequiredString(record, \"cliVersion\", filePath),\n runtimeVersion: readRequiredString(record, \"runtimeVersion\", filePath),\n manifestHash: readRequiredString(record, \"manifestHash\", filePath),\n artifacts: artifactsValue.map((artifact, index) =>\n readArtifactMetadata(artifact, index),\n ),\n };\n}\n\nfunction readArtifactMetadata(value: unknown, index: number): ArtifactMetadata {\n if (!isRecord(value) || Array.isArray(value)) {\n throw new Error(\n `publish-manifest.json artifacts[${index}] must be a JSON object.`,\n );\n }\n\n return {\n path: readRequiredString(value, \"path\", \"publish-manifest.json\"),\n sha256: readRequiredString(value, \"sha256\", \"publish-manifest.json\"),\n bytes: readRequiredNumber(value, \"bytes\", \"publish-manifest.json\"),\n contentType: readRequiredString(\n value,\n \"contentType\",\n \"publish-manifest.json\",\n ),\n };\n}\n\nasync function readUploadArtifacts(\n publishDir: string,\n artifacts: readonly ArtifactMetadata[],\n): Promise<WidgetPackagePublishRequest[\"artifacts\"]> {\n const resolvedPublishDir = path.resolve(publishDir);\n\n return Promise.all(\n artifacts.map(async (artifact) => {\n const artifactPath = resolveArtifactPath(\n resolvedPublishDir,\n artifact.path,\n );\n const actual = await computeArtifactMetadata(\n artifactPath,\n resolvedPublishDir,\n );\n assertArtifactMetadataMatches(artifact, actual);\n\n return {\n ...actual,\n body: await fs.readFile(artifactPath),\n };\n }),\n );\n}\n\nfunction assertManifestIdentityMatches(\n manifest: Record<string, unknown>,\n publishManifest: PublishManifestMetadata,\n manifestPath: string,\n): void {\n assertMetadataMatches({\n label: \"packageId\",\n path: \"manifest.json\",\n expected: publishManifest.packageId,\n actual: readRequiredString(manifest, \"packageId\", manifestPath),\n });\n assertMetadataMatches({\n label: \"version\",\n path: \"manifest.json\",\n expected: publishManifest.version,\n actual: readRequiredString(manifest, \"version\", manifestPath),\n });\n}\n\nfunction assertArtifactInventoryMatches(\n expected: readonly ArtifactMetadata[],\n actual: readonly ArtifactMetadata[],\n): void {\n const expectedByPath = new Map<string, ArtifactMetadata>();\n for (const artifact of expected) {\n if (expectedByPath.has(artifact.path)) {\n throw new Error(\n `publish-manifest.json artifacts include duplicate path ${JSON.stringify(artifact.path)}. ` +\n \"Rebuild the widget package before publishing.\",\n );\n }\n expectedByPath.set(artifact.path, artifact);\n }\n\n const actualPaths = new Set<string>();\n for (const actualArtifact of actual) {\n actualPaths.add(actualArtifact.path);\n const expectedArtifact = expectedByPath.get(actualArtifact.path);\n if (!expectedArtifact) {\n throw new Error(\n `publish-manifest.json artifacts omit ${JSON.stringify(actualArtifact.path)}. ` +\n \"Rebuild the widget package before publishing.\",\n );\n }\n assertArtifactMetadataMatches(expectedArtifact, actualArtifact);\n }\n\n for (const expectedArtifact of expected) {\n if (actualPaths.has(expectedArtifact.path)) continue;\n throw new Error(\n `publish-manifest.json artifacts include ${JSON.stringify(expectedArtifact.path)}, but that file is not present on disk. ` +\n \"Rebuild the widget package before publishing.\",\n );\n }\n}\n\nfunction assertArtifactMetadataMatches(\n expected: ArtifactMetadata,\n actual: ArtifactMetadata,\n): void {\n assertMetadataMatches({\n label: \"path\",\n path: expected.path,\n expected: expected.path,\n actual: actual.path,\n });\n assertMetadataMatches({\n label: \"sha256\",\n path: expected.path,\n expected: expected.sha256,\n actual: actual.sha256,\n });\n assertMetadataMatches({\n label: \"bytes\",\n path: expected.path,\n expected: expected.bytes,\n actual: actual.bytes,\n });\n assertMetadataMatches({\n label: \"contentType\",\n path: expected.path,\n expected: expected.contentType,\n actual: actual.contentType,\n });\n}\n\nfunction assertMetadataMatches(options: {\n readonly label: string;\n readonly path: string;\n readonly expected: string | number;\n readonly actual: string | number;\n}): void {\n if (options.expected === options.actual) return;\n\n throw new Error(\n `publish-manifest.json ${options.label} for ${JSON.stringify(options.path)} does not match the file on disk. ` +\n `Recorded ${JSON.stringify(options.expected)}, computed ${JSON.stringify(options.actual)}. ` +\n \"Rebuild the widget package before publishing.\",\n );\n}\n\nfunction resolveArtifactPath(publishDir: string, artifactPath: string): string {\n const resolved = path.resolve(publishDir, artifactPath);\n const relative = path.relative(publishDir, resolved);\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) {\n throw new Error(\n `Artifact path ${JSON.stringify(artifactPath)} escapes the publish directory.`,\n );\n }\n return resolved;\n}\n\nfunction stripOwnerPrefix(\n packageId: string,\n owner: WidgetPackageBuildOwner,\n): string {\n const prefix = `${owner}.`;\n if (packageId.startsWith(prefix) && packageId.length > prefix.length) {\n return packageId.slice(prefix.length);\n }\n return packageId;\n}\n\nfunction readRequiredString(\n record: Record<string, unknown>,\n key: string,\n filePath: string,\n): string {\n const value = record[key];\n if (typeof value === \"string\" && value.trim().length > 0) return value;\n throw new Error(`${path.basename(filePath)} must include string ${key}.`);\n}\n\nfunction readRequiredNumber(\n record: Record<string, unknown>,\n key: string,\n filePath: string,\n): number {\n const value = record[key];\n if (typeof value === \"number\" && Number.isFinite(value)) return value;\n throw new Error(`${path.basename(filePath)} must include number ${key}.`);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n","import { Command } from \"commander\";\nimport type { PluginContext } from \"@fluid-app/fluid-cli\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport type { PortalDeployOptions } from \"../types.js\";\nimport {\n createAuthenticatedWidgetPackageClient,\n printRuntimeOnlyNotice,\n printDryRunSessionPayload,\n printWidgetPublishSummary,\n publishWidgetRuntimeArtifacts,\n} from \"./widget-package-publish.js\";\n\nconst DEFAULT_OUT_DIR = \".fluid/widget-dist\";\nconst DEFAULT_ENVIRONMENT = \"production\";\n\nexport const deployCommand: Command = new Command(\"deploy\")\n .description(\"Publish company-owned portal widget runtime artifacts\")\n .option(\n \"-e, --environment <name>\",\n \"Target environment label for output reporting\",\n DEFAULT_ENVIRONMENT,\n )\n .option(\n \"-o, --out-dir <dir>\",\n \"Widget artifact output directory\",\n DEFAULT_OUT_DIR,\n )\n .option(\"--dry-run\", \"Build and validate upload payload without publishing\")\n .action(async (options: PortalDeployOptions) => {\n const environment = options.environment ?? DEFAULT_ENVIRONMENT;\n const outDir = options.outDir ?? DEFAULT_OUT_DIR;\n const dryRun = options.dryRun === true;\n\n console.log();\n console.log(chalk.blue.bold(\"Fluid Portal Deploy\"));\n console.log();\n printRuntimeOnlyNotice();\n console.log(chalk.gray(\"Environment: \") + chalk.white(environment));\n console.log(chalk.gray(\"Output: \") + chalk.cyan(outDir));\n if (dryRun)\n console.log(chalk.yellow(\"Dry run: no upload will be created.\"));\n console.log();\n\n const spinner = ora(\"Building company-owned widget package...\").start();\n\n try {\n const result = await publishWidgetRuntimeArtifacts({\n projectDir: process.cwd(),\n outDir,\n buildOwner: \"company\",\n uploadOwner: { kind: \"company\" },\n dryRun,\n ...(dryRun ? {} : { client: createAuthenticatedWidgetPackageClient() }),\n });\n\n spinner.succeed(\"Built widget runtime artifacts\");\n\n if (dryRun) {\n console.log(\n chalk.yellow(\"Dry run complete — upload session was not requested.\"),\n );\n console.log();\n printDryRunSessionPayload(result);\n } else {\n console.log(chalk.green(\"Published widget package version.\"));\n }\n\n printWidgetPublishSummary({\n title: dryRun ? \"Portal deploy dry run\" : \"Portal deploy\",\n ownerLabel: \"company\",\n environment,\n outDir,\n result,\n });\n } catch (err) {\n spinner.fail(\"Portal deploy failed\");\n console.error(\n chalk.red(\"Error:\") +\n \" \" +\n (err instanceof Error ? err.message : String(err)),\n );\n process.exit(1);\n }\n });\n\nexport function registerDeployCommand(ctx: PluginContext): void {\n ctx.program.addCommand(deployCommand);\n}\n","import { Command } from \"commander\";\nimport type { PluginContext } from \"@fluid-app/fluid-cli\";\nimport chalk from \"chalk\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * Severity levels for drift diagnostics.\n * - ERROR: Security-critical or breaking drift (e.g., missing CSP)\n * - WARN: Stale config that may cause subtle issues\n * - INFO: Cosmetic or non-functional differences\n */\nexport type Severity = \"error\" | \"warn\" | \"info\";\n\nexport interface Diagnostic {\n file: string;\n severity: Severity;\n message: string;\n}\n\n/** Files that are managed by the SDK and should match the canonical template. */\nconst INFRASTRUCTURE_FILES = [\n \"index.html\",\n \"tsconfig.json\",\n \"vite.config.ts\",\n \".oxlintrc.json\",\n] as const;\n\n/** Entry files with expected content patterns after Phase 2 absorption. */\nconst ENTRY_CHECKS = [\n {\n file: \"src/main.tsx\",\n expectedPattern: \"createPortal\",\n hint: 'main.tsx should use createPortal() from @fluid-app/portal-sdk. Run \"fluid create\" to see the latest template.',\n },\n {\n file: \"src/index.css\",\n expectedPattern: \"@fluid-app/portal-sdk/globals.css\",\n hint: \"index.css should import @fluid-app/portal-sdk/globals.css instead of inline theme tokens.\",\n },\n] as const;\n\n/** Files that should NOT exist after Phase 2 (absorbed into SDK). */\nconst REMOVED_FILES = [\n {\n file: \"src/App.tsx\",\n hint: \"App.tsx is no longer needed — createPortal() handles the AppShell wiring internally.\",\n },\n {\n file: \"src/fluid.config.ts\",\n hint: \"fluid.config.ts is no longer needed — pass config overrides to createPortal() directly.\",\n },\n] as const;\n\nfunction readFileOrNull(filePath: string): string | null {\n try {\n return readFileSync(filePath, \"utf-8\");\n } catch {\n return null;\n }\n}\n\nconst _currentFile = fileURLToPath(import.meta.url);\nconst _currentDir = dirname(_currentFile);\n\nfunction findTemplateDir(): string | null {\n // Walk up from current file to find package root (works in both dist/ and src/)\n let dir = _currentDir;\n while (!existsSync(join(dir, \"package.json\"))) {\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n const templateDir = join(dir, \"templates\");\n if (existsSync(join(templateDir, \"base\"))) return templateDir;\n return null;\n}\n\nexport function checkInfrastructureDrift(\n cwd: string,\n templateDir: string,\n): Diagnostic[] {\n const diagnostics: Diagnostic[] = [];\n\n for (const file of INFRASTRUCTURE_FILES) {\n const portalPath = join(cwd, file);\n const templatePath = join(templateDir, \"base\", file);\n\n if (!existsSync(portalPath)) {\n diagnostics.push({\n file,\n severity: \"warn\",\n message: `Missing file: ${file}`,\n });\n continue;\n }\n\n if (!existsSync(templatePath)) {\n // Template doesn't have this file — skip\n continue;\n }\n\n const portalContent = readFileOrNull(portalPath);\n const templateContent = readFileOrNull(templatePath);\n\n if (portalContent !== null && templateContent !== null) {\n if (portalContent.trim() !== templateContent.trim()) {\n diagnostics.push({\n file,\n severity: \"warn\",\n message: `Content differs from canonical template. Review and update if needed.`,\n });\n }\n }\n }\n\n return diagnostics;\n}\n\nexport function checkEntryPatterns(cwd: string): Diagnostic[] {\n const diagnostics: Diagnostic[] = [];\n\n for (const check of ENTRY_CHECKS) {\n const filePath = join(cwd, check.file);\n const content = readFileOrNull(filePath);\n\n if (content === null) {\n diagnostics.push({\n file: check.file,\n severity: \"error\",\n message: `Missing file. ${check.hint}`,\n });\n continue;\n }\n\n if (!content.includes(check.expectedPattern)) {\n diagnostics.push({\n file: check.file,\n severity: \"warn\",\n message: `Does not contain expected pattern \"${check.expectedPattern}\". ${check.hint}`,\n });\n }\n }\n\n return diagnostics;\n}\n\nexport function checkRemovedFiles(cwd: string): Diagnostic[] {\n const diagnostics: Diagnostic[] = [];\n\n for (const check of REMOVED_FILES) {\n if (existsSync(join(cwd, check.file))) {\n diagnostics.push({\n file: check.file,\n severity: \"info\",\n message: `File can be removed. ${check.hint}`,\n });\n }\n }\n\n return diagnostics;\n}\n\nfunction formatDiagnostic(d: Diagnostic): string {\n const icon =\n d.severity === \"error\"\n ? chalk.red(\"ERROR\")\n : d.severity === \"warn\"\n ? chalk.yellow(\" WARN\")\n : chalk.blue(\" INFO\");\n\n return ` ${icon} ${chalk.bold(d.file)}\\n ${chalk.dim(d.message)}`;\n}\n\nexport const doctorCommand: Command = new Command(\"doctor\")\n .description(\n \"Check portal for scaffold drift and report stale infrastructure files\",\n )\n .action(async () => {\n const cwd = process.cwd();\n\n // Validate we're in a portal project\n const packageJsonPath = join(cwd, \"package.json\");\n if (!existsSync(packageJsonPath)) {\n console.error(\n chalk.red(\"Error: No package.json found in current directory\"),\n );\n console.error(\n chalk.yellow(\"Make sure you're in a Fluid portal project directory\"),\n );\n process.exit(1);\n }\n\n let packageJson: {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n try {\n packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf-8\"));\n } catch {\n console.error(chalk.red(\"Error: Could not parse package.json\"));\n console.error(chalk.yellow(\"Ensure package.json contains valid JSON\"));\n process.exit(1);\n }\n const deps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n if (!deps[\"@fluid-app/portal-sdk\"]) {\n console.error(\n chalk.red(\"Error: @fluid-app/portal-sdk not found in dependencies\"),\n );\n console.error(\n chalk.yellow(\n \"This command must be run from a Fluid portal project directory\",\n ),\n );\n process.exit(1);\n }\n\n console.log();\n console.log(chalk.bold(\"Fluid Portal Doctor\"));\n console.log(chalk.dim(\"Checking for scaffold drift...\\n\"));\n\n const diagnostics: Diagnostic[] = [];\n\n // Check entry file patterns\n diagnostics.push(...checkEntryPatterns(cwd));\n\n // Check for files that should be removed\n diagnostics.push(...checkRemovedFiles(cwd));\n\n // Check infrastructure drift against templates (if available)\n const templateDir = findTemplateDir();\n if (templateDir) {\n diagnostics.push(...checkInfrastructureDrift(cwd, templateDir));\n } else {\n console.log(\n chalk.dim(\n \" (Skipping infrastructure diff — template files not available)\\n\",\n ),\n );\n }\n\n // Report results\n if (diagnostics.length === 0) {\n console.log(chalk.green(\" All clear — no drift detected.\\n\"));\n return;\n }\n\n const errors = diagnostics.filter((d) => d.severity === \"error\");\n const warns = diagnostics.filter((d) => d.severity === \"warn\");\n const infos = diagnostics.filter((d) => d.severity === \"info\");\n\n for (const d of [...errors, ...warns, ...infos]) {\n console.log(formatDiagnostic(d));\n console.log();\n }\n\n // Summary\n const parts: string[] = [];\n if (errors.length > 0) parts.push(chalk.red(`${errors.length} error(s)`));\n if (warns.length > 0)\n parts.push(chalk.yellow(`${warns.length} warning(s)`));\n if (infos.length > 0) parts.push(chalk.blue(`${infos.length} info`));\n console.log(` ${parts.join(\", \")}\\n`);\n\n if (errors.length > 0) {\n process.exit(1);\n }\n });\n\nexport function registerDoctorCommand(ctx: PluginContext): void {\n ctx.program.addCommand(doctorCommand);\n}\n","import { Command } from \"commander\";\nimport type { PluginContext } from \"@fluid-app/fluid-cli\";\nimport { getAuthToken } from \"@fluid-app/fluid-cli\";\nimport chalk from \"chalk\";\nimport { createFetchClient, fluidOs } from \"@fluid-app/fluidos-api-client\";\nimport prompts from \"prompts\";\nimport path from \"node:path\";\nimport { readMappings } from \"../utils/mappings.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst PORTAL_SYNC_DIR = \".portal-sync\";\n\nfunction getApiBase(): string {\n return process.env[\"FLUID_API_BASE\"] ?? \"https://api.fluid.app\";\n}\n\nfunction requireToken(): string {\n const token = getAuthToken();\n if (!token) {\n console.error(\n chalk.red(\"Error:\") +\n \" Not logged in. Run \" +\n chalk.cyan(\"`fluid login`\") +\n \" first.\",\n );\n process.exit(1);\n }\n return token;\n}\n\nfunction createClient(token: string) {\n return createFetchClient({\n baseUrl: getApiBase(),\n getAuthToken: () => token,\n });\n}\n\nasync function requireDefinitionId(): Promise<number> {\n const cwd = process.cwd();\n const mappings = await readMappings(path.join(cwd, PORTAL_SYNC_DIR));\n if (!mappings) {\n console.error(\n chalk.red(\"Error:\") +\n \" No definition pulled. Run \" +\n chalk.cyan(\"`fluid portal pull`\") +\n \" first.\",\n );\n process.exit(1);\n }\n return mappings.definition.id;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Subcommands\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst createVersionCommand = new Command(\"create\")\n .description(\"Create a new version (snapshot) of the portal definition\")\n .option(\"--activate\", \"Activate the version immediately after creation\")\n .action(async (options: { activate?: boolean }) => {\n const token = requireToken();\n const client = createClient(token);\n const definitionId = await requireDefinitionId();\n\n console.log();\n console.log(chalk.bold(\"Creating version...\"));\n\n let result;\n try {\n result = await fluidOs.fluid_os_v0_create_fluid_osversion(\n client,\n definitionId,\n );\n } catch (err) {\n console.error(\n chalk.red(\"Error:\") +\n \" Failed to create version — \" +\n (err instanceof Error ? err.message : String(err)),\n );\n process.exit(1);\n }\n\n const version = result.version;\n\n if (!version?.id) {\n console.error(\n chalk.red(\"Error:\") +\n \" Failed to create version — unexpected response.\",\n );\n process.exit(1);\n }\n\n console.log();\n console.log(chalk.green(\"Version created successfully.\"));\n console.log();\n console.log(chalk.gray(\"Version ID: \") + chalk.white(version.id));\n\n let active = version.active ?? false;\n\n if (options.activate) {\n console.log(\"Activating version...\");\n try {\n await fluidOs.fluid_os_v0_update_fluid_osversion(\n client,\n definitionId,\n version.id,\n {\n version: { active: true },\n },\n );\n } catch (err) {\n console.error(\n chalk.red(\"Error:\") +\n \" Failed to activate version — \" +\n (err instanceof Error ? err.message : String(err)),\n );\n process.exit(1);\n }\n active = true;\n }\n\n console.log(\n chalk.gray(\"Active: \") +\n (active ? chalk.green(\"yes\") : chalk.gray(\"no\")),\n );\n console.log();\n });\n\nconst listVersionCommand = new Command(\"list\")\n .description(\"List all versions of the portal definition\")\n .action(async () => {\n const token = requireToken();\n const client = createClient(token);\n const definitionId = await requireDefinitionId();\n\n let result;\n try {\n result = await fluidOs.fluid_os_v0_list_fluid_osversions(\n client,\n definitionId,\n );\n } catch (err) {\n console.error(\n chalk.red(\"Error:\") +\n \" Failed to list versions — \" +\n (err instanceof Error ? err.message : String(err)),\n );\n process.exit(1);\n }\n\n const versions = result.version;\n\n if (!Array.isArray(versions) || versions.length === 0) {\n console.log();\n console.log(chalk.yellow(\"No versions found.\"));\n console.log(\n \"Run \" +\n chalk.cyan(\"`fluid portal version create`\") +\n \" to publish a version.\",\n );\n console.log();\n return;\n }\n\n console.log();\n\n // Print table header\n const COL_ID = \"Version ID\".padEnd(36);\n const COL_ACT = \"Active\".padEnd(6);\n const COL_PUB = \"Published\";\n console.log(chalk.gray(` ${COL_ID} ${COL_ACT} ${COL_PUB}`));\n\n for (const v of versions) {\n const id = String(v.id).padEnd(36);\n const active = v.active ? chalk.green(\"\\u2713\") + \" \" : \" \";\n const published = v.published_at\n ? new Date(v.published_at).toLocaleString()\n : \"\\u2014\";\n console.log(` ${id} ${active} ${published}`);\n }\n\n console.log();\n });\n\nconst activateVersionCommand = new Command(\"activate\")\n .description(\"Activate a specific version, making it the live version\")\n .argument(\"<version-id>\", \"The version ID to activate\")\n .option(\"-y, --yes\", \"Skip confirmation prompt\")\n .action(async (versionId: string, options: { yes?: boolean }) => {\n const token = requireToken();\n const client = createClient(token);\n const definitionId = await requireDefinitionId();\n\n if (!options.yes) {\n const { confirm } = await prompts({\n type: \"confirm\",\n name: \"confirm\",\n message: `Activate version ${versionId}? This will make it the live version.`,\n initial: false,\n });\n\n if (!confirm) {\n console.log(chalk.yellow(\"Aborted.\"));\n return;\n }\n }\n\n console.log();\n console.log(chalk.bold(\"Activating version...\"));\n\n try {\n await fluidOs.fluid_os_v0_update_fluid_osversion(\n client,\n definitionId,\n versionId,\n {\n version: { active: true },\n },\n );\n } catch (err) {\n console.error(\n chalk.red(\"Error:\") +\n \" Failed to activate version — \" +\n (err instanceof Error ? err.message : String(err)),\n );\n process.exit(1);\n }\n\n console.log();\n console.log(chalk.green(\"Version \" + versionId + \" is now active.\"));\n console.log();\n });\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Version command group\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const versionCommand: Command = new Command(\"version\")\n .description(\"Manage portal definition versions\")\n .addCommand(createVersionCommand)\n .addCommand(listVersionCommand)\n .addCommand(activateVersionCommand);\n\nexport function registerVersionCommand(ctx: PluginContext): void {\n ctx.program.addCommand(versionCommand);\n}\n","import { Command } from \"commander\";\nimport type { PluginContext } from \"@fluid-app/fluid-cli\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport type { WidgetPublishOptions } from \"../types.js\";\nimport {\n createAuthenticatedWidgetPackageClient,\n printDryRunSessionPayload,\n printWidgetPublishSummary,\n printRuntimeOnlyNotice,\n publishWidgetRuntimeArtifacts,\n} from \"./widget-package-publish.js\";\n\nconst DEFAULT_OUT_DIR = \".fluid/widget-dist\";\n\nconst publishSubcommand = new Command(\"publish\")\n .description(\"Publish droplet-owned widget runtime artifacts\")\n .requiredOption(\n \"--droplet <uuid>\",\n \"Droplet UUID that owns the widget package\",\n )\n .option(\n \"-o, --out-dir <dir>\",\n \"Widget artifact output directory\",\n DEFAULT_OUT_DIR,\n )\n .option(\"--dry-run\", \"Build and validate upload payload without publishing\")\n .action(async (options: WidgetPublishOptions) => {\n const outDir = options.outDir ?? DEFAULT_OUT_DIR;\n const dryRun = options.dryRun === true;\n\n console.log();\n console.log(chalk.blue.bold(\"Fluid Widget Publish\"));\n console.log();\n printRuntimeOnlyNotice();\n console.log(chalk.gray(\"Droplet: \") + chalk.white(options.droplet));\n console.log(chalk.gray(\"Output: \") + chalk.cyan(outDir));\n if (dryRun)\n console.log(chalk.yellow(\"Dry run: no upload will be created.\"));\n console.log();\n\n const spinner = ora(\"Building droplet-owned widget package...\").start();\n\n try {\n const result = await publishWidgetRuntimeArtifacts({\n projectDir: process.cwd(),\n outDir,\n buildOwner: \"droplet\",\n uploadOwner: { kind: \"droplet\", uuid: options.droplet },\n dryRun,\n ...(dryRun ? {} : { client: createAuthenticatedWidgetPackageClient() }),\n });\n\n spinner.succeed(\"Built widget runtime artifacts\");\n\n if (dryRun) {\n console.log(\n chalk.yellow(\"Dry run complete — upload session was not requested.\"),\n );\n console.log();\n printDryRunSessionPayload(result);\n } else {\n console.log(chalk.green(\"Published widget package version.\"));\n }\n\n printWidgetPublishSummary({\n title: dryRun ? \"Widget publish dry run\" : \"Widget publish\",\n ownerLabel: `droplet ${options.droplet}`,\n outDir,\n result,\n });\n } catch (err) {\n spinner.fail(\"Widget publish failed\");\n console.error(\n chalk.red(\"Error:\") +\n \" \" +\n (err instanceof Error ? err.message : String(err)),\n );\n process.exit(1);\n }\n });\n\nexport const topLevelWidgetCommand: Command = new Command(\"widget\")\n .description(\"Publish Fluid widget packages\")\n .addCommand(publishSubcommand);\n\nexport function registerTopLevelWidgetCommand(ctx: PluginContext): void {\n ctx.program.addCommand(topLevelWidgetCommand);\n}\n","/**\n * @fluid-app/fluid-cli-portal\n *\n * Fluid CLI plugin for building portal applications.\n * Auto-discovered by @fluid-app/fluid-cli via the fluid-cli-* naming convention.\n */\n\nimport { Command } from \"commander\";\nimport type { FluidPlugin, PluginContext } from \"@fluid-app/fluid-cli\";\nimport { createCommand } from \"./commands/create.js\";\nimport { devCommand } from \"./commands/dev.js\";\nimport { buildCommand } from \"./commands/build.js\";\nimport { pullCommand } from \"./commands/pull.js\";\nimport { pushCommand } from \"./commands/push.js\";\nimport { widgetCommand } from \"./commands/widget-create.js\";\nimport { deployCommand } from \"./commands/deploy.js\";\nimport { doctorCommand } from \"./commands/doctor.js\";\nimport { versionCommand } from \"./commands/version.js\";\n\nconst plugin: FluidPlugin = {\n name: \"fluid-cli-portal\",\n version: \"0.1.0\",\n async register(ctx: PluginContext) {\n const portal = new Command(\"portal\").description(\n \"Build and develop portal applications\",\n );\n\n portal.addCommand(createCommand);\n portal.addCommand(devCommand);\n portal.addCommand(buildCommand);\n portal.addCommand(pullCommand);\n portal.addCommand(pushCommand);\n portal.addCommand(deployCommand);\n portal.addCommand(widgetCommand);\n portal.addCommand(doctorCommand);\n portal.addCommand(versionCommand);\n\n ctx.program.addCommand(portal);\n },\n};\n\nexport default plugin;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Re-exports for programmatic usage (e.g., @fluid-app/create-portal-app)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type {\n ProjectConfig,\n CreateOptions,\n DevOptions,\n BuildOptions,\n TemplateVariables,\n SelectedPageTemplate,\n TemplateName,\n WidgetCreateOptions,\n PortalDeployOptions,\n WidgetPublishOptions,\n} from \"./types.js\";\n\nexport { TEMPLATES } from \"./types.js\";\n\nexport {\n getInstallCommand,\n getRunCommand,\n runPackageManager,\n installDependencies,\n} from \"./utils/package-manager.js\";\n\nexport {\n getTemplatePaths,\n copyTemplate,\n directoryExists,\n fileExists,\n pathExists,\n createDirectory,\n getSdkVersion,\n readFileSafe,\n writeFileSafe,\n createDirectorySafe,\n copyTemplateSafe,\n getSdkVersionSafe,\n FILE_SYSTEM_ERRORS,\n type FileSystemErrorCode,\n type FileSystemError,\n type TemplatePaths,\n} from \"./utils/file-system.js\";\n\nexport { promptProjectConfig } from \"./utils/prompts.js\";\n\n// Expose the standalone Command for create-portal-app\nexport { createCommand } from \"./commands/create.js\";\nexport { pullCommand } from \"./commands/pull.js\";\nexport { pushCommand } from \"./commands/push.js\";\nexport { widgetCommand } from \"./commands/widget-create.js\";\nexport { topLevelWidgetCommand } from \"./commands/widget-publish.js\";\nexport { deployCommand } from \"./commands/deploy.js\";\nexport { versionCommand } from \"./commands/version.js\";\nexport { doctorCommand } from \"./commands/doctor.js\";\n\nexport {\n readMappings,\n writeMappings,\n deriveSlug,\n resolveSlugToId,\n resolveIdToSlug,\n updateMapping,\n removeMapping,\n type PortalMappings,\n type DefinitionMapping,\n type MappedResourceType,\n} from \"./utils/mappings.js\";\n\nexport {\n computeFileHash,\n readSnapshot,\n writeSnapshot,\n diffAgainstSnapshot,\n buildSnapshot,\n type Snapshot,\n type SnapshotDiff,\n type FileHash,\n type FileHashMap,\n} from \"./utils/snapshot.js\";\n\nexport {\n transformScreen,\n deriveScreenSlug,\n transformTheme,\n transformNavigation,\n transformNavigationItems,\n transformProfile,\n buildIdToSlugMap,\n buildNavigationIdToSlugMap,\n buildThemeIdToSlugMap,\n type LocalScreen,\n type LocalTheme,\n type LocalNavigation,\n type LocalNavigationItem,\n type LocalProfile,\n} from \"./utils/transform.js\";\n\nexport {\n categorizeChanges,\n validateCrossReferences,\n slugFromPath,\n type CategorizedChanges,\n type ValidationError,\n} from \"./utils/push-validation.js\";\n\nexport {\n buildSharedWidgetPackage,\n createWidgetPackageEntrySource,\n type BuildSharedWidgetPackageOptions,\n type SharedWidgetPackageBuildResult,\n type SharedWidgetPackageBuildError,\n} from \"./utils/widget-package-builder.js\";\n\nexport {\n resolvePortalWidgetSourceConfig,\n loadSourceWidgetPackages,\n type WidgetSourceConfig,\n type WidgetSourceConfigLoadError,\n} from \"./utils/widget-package-config.js\";\n\nexport {\n validateSingleSourceWidgetPackage,\n buildWidgetPackageDescriptor,\n type SourceWidgetMetadata,\n type SourceWidgetPackageMetadata,\n type WidgetDescriptorMetadata,\n type WidgetPackageDescriptorMetadata,\n type ValidatedWidgetPackageBuild,\n type WidgetPackageValidationErrorCode,\n type WidgetPackageValidationError,\n type WidgetPackageValidationResult,\n type ValidateSourceWidgetPackageOptions,\n type WidgetPackageOwnerKind,\n} from \"./utils/widget-package-validation.js\";\n\nexport {\n WIDGET_PACKAGE_BUILDER_VERSION,\n computeArtifactMetadata,\n collectWidgetPackageArtifacts,\n createPublishManifestMetadata,\n getArtifactContentType,\n sha256,\n type ArtifactMetadata,\n type PublishManifestMetadata,\n} from \"./utils/widget-package-artifacts.js\";\n\nexport {\n publishWidgetRuntimeArtifacts,\n createWidgetPackagePublishRequest,\n createAuthenticatedWidgetPackageClient,\n printDryRunSessionPayload,\n printWidgetPublishSummary,\n printRuntimeOnlyNotice,\n validateWidgetPublishOutDir,\n type PublishWidgetRuntimeArtifactsOptions,\n type PublishWidgetRuntimeArtifactsResult,\n type PublishWidgetRuntimeArtifactsDependencies,\n} from \"./commands/widget-package-publish.js\";\n\nexport {\n buildWidgetPackageUploadSessionPayload,\n getWidgetPackageUploadSessionRoute,\n getWidgetPackageCompleteUploadRoute,\n requestWidgetPackageUploadSession,\n uploadWidgetPackageArtifacts,\n completeWidgetPackageUpload,\n publishWidgetPackageVersion,\n normalizeWidgetPackageUploadSession,\n normalizeWidgetPackageCompleteResponse,\n buildWidgetPackageCompleteUploadPayload,\n WidgetPackageUploadError,\n type WidgetPackageUploadOwner,\n type WidgetPackageArtifactMetadata,\n type WidgetPackageUploadArtifact,\n type WidgetPackageSessionRequest,\n type WidgetPackagePublishRequest,\n type WidgetPackageArtifactPayload,\n type WidgetPackageUploadSessionPayload,\n type WidgetPackageCompleteUploadPayload,\n type WidgetPackageSignedUpload,\n type WidgetPackageUploadSession,\n type WidgetPackageArtifactUploadResult,\n type WidgetPackageCompleteResult,\n type WidgetPackagePublishResult,\n type PublishWidgetPackageVersionOptions,\n type WidgetPackageUploadFetch,\n} from \"./utils/widget-package-upload.js\";\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["_currentDir","PORTAL_DIR","TSX_CLI_PATH","createTempDirectory","isRecord","path","isRecord","readPortalFile","PORTAL_SYNC_DIR","createClient","fluidOs.fluid_os_v0_create_fluid_osscreen","fluidOs.fluid_os_v0_update_fluid_osscreen","fluidOs.fluid_os_v0_delete_fluid_osscreen","fluidOs.fluid_os_v0_create_fluid_ostheme","fluidOs.fluid_os_v0_update_fluid_ostheme","fluidOs.fluid_os_v0_delete_fluid_ostheme","fluidOs.fluid_os_v0_create_fluid_osnavigation","fluidOs.fluid_os_v0_create_fluid_osnavigation_item","fluidOs.fluid_os_v0_update_fluid_osnavigation","fluidOs.fluid_os_v0_list_fluid_osnavigation_items","fluidOs.fluid_os_v0_delete_fluid_osnavigation_item","fluidOs.fluid_os_v0_update_fluid_osnavigation_item","fluidOs.fluid_os_v0_delete_fluid_osnavigation","fluidOs.fluid_os_v0_create_fluid_osprofile","fluidOs.fluid_os_v0_update_fluid_osprofile","fluidOs.fluid_os_v0_delete_fluid_osprofile","toPosixPath","isRecord","isRecord","fluidOs.fluid_os_v0_create_widget_package_version","fluidOs.fluid_os_v0_complete_widget_package_version_upload","isRecord","DEFAULT_OUT_DIR","fluidOs.fluid_os_v0_create_fluid_osversion","fluidOs.fluid_os_v0_update_fluid_osversion","fluidOs.fluid_os_v0_list_fluid_osversions"],"sources":["../src/types.ts","../src/utils/prompts.ts","../src/utils/file-system.ts","../src/utils/package-manager.ts","../src/commands/create.ts","../src/commands/dev.ts","../src/utils/widget-package-config.ts","../src/utils/extract-manifests.ts","../src/commands/build.ts","../src/utils/push-validation.ts","../src/commands/push.ts","../src/utils/widget-helpers.ts","../src/commands/widget-create.ts","../src/utils/widget-package-artifacts.ts","../src/utils/widget-package-validation.ts","../src/utils/widget-package-builder.ts","../src/utils/widget-package-upload.ts","../src/commands/widget-package-publish.ts","../src/commands/deploy.ts","../src/commands/doctor.ts","../src/commands/version.ts","../src/commands/widget-publish.ts","../src/index.ts"],"sourcesContent":["// ─────────────────────────────────────────────────────────────────────────────\n// Template types - derived from const object\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Available project templates\n */\nexport const TEMPLATES = {\n starter: \"starter\",\n} as const;\n\n/**\n * Union type of valid template names\n */\nexport type TemplateName = (typeof TEMPLATES)[keyof typeof TEMPLATES];\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Project configuration types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Selected page template info\n */\nexport interface SelectedPageTemplate {\n readonly id: string;\n readonly slug: string;\n readonly name: string;\n}\n\n/**\n * Configuration options collected during project scaffolding\n */\nexport interface ProjectConfig {\n /** Project name (used for directory and package.json name) */\n readonly name: string;\n /** Whether to install dependencies after scaffolding */\n readonly installDeps: boolean;\n /** Selected optional page templates to include */\n readonly selectedPages: readonly SelectedPageTemplate[];\n /** CLI profile name for .fluidrc (empty string if none selected) */\n readonly profileName: string;\n}\n\n/**\n * Options for the create command (from CLI arguments)\n */\nexport interface CreateOptions {\n /** Skip dependency installation */\n readonly skipInstall?: boolean;\n /** Directory to create the project in (defaults to cwd) */\n readonly outputDir?: string;\n /** Use local monorepo packages via file: links instead of npm versions */\n readonly local?: boolean;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Command option types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Options for the dev command\n */\nexport interface DevOptions {\n readonly port?: number;\n readonly host?: boolean;\n}\n\n/**\n * Options for the build command\n */\nexport interface BuildOptions {\n readonly outDir?: string;\n}\n\n/**\n * Options for the widget create command\n */\nexport interface WidgetCreateOptions {\n /** Category for palette grouping */\n readonly category?: string;\n}\n\n/**\n * Options for the portal deploy command\n */\nexport interface PortalDeployOptions {\n readonly environment?: string;\n readonly outDir?: string;\n readonly dryRun?: boolean;\n}\n\n/**\n * Options for the top-level widget publish command\n */\nexport interface WidgetPublishOptions {\n readonly droplet: string;\n readonly outDir?: string;\n readonly dryRun?: boolean;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Template processing types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Template variables for Handlebars processing\n */\nexport interface TemplateVariables {\n readonly projectName: string;\n readonly sdkVersion: string;\n /** portal-core link used only for --local scaffolds */\n readonly localCoreVersion?: string;\n /** CLI package version (versioned independently from the SDK) */\n readonly cliVersion: string;\n /** Selected page templates for the project */\n readonly selectedPages: readonly SelectedPageTemplate[];\n /** Whether any optional pages were selected */\n readonly hasSelectedPages: boolean;\n /** CLI profile name for .fluidrc */\n readonly profileName: string;\n}\n","import { getActiveProfile, listProfileNames } from \"@fluid-app/fluid-cli\";\nimport prompts from \"prompts\";\nimport {\n type ProjectConfig,\n type CreateOptions,\n type SelectedPageTemplate,\n} from \"../types.js\";\n\n/**\n * Optional page template shape\n */\ninterface OptionalPageTemplate {\n readonly id: string;\n readonly slug: string;\n readonly name: string;\n readonly description: string;\n}\n\n/**\n * Available optional page templates that can be selected during project creation.\n * Core pages (Messaging, Contacts, CRM) are always included automatically.\n */\nconst OPTIONAL_PAGE_TEMPLATES: readonly OptionalPageTemplate[] = [\n // Currently no optional pages - all pages are core\n // Future optional pages can be added here:\n // { id: 'orders', slug: 'orders', name: 'Orders', description: 'Order management page' },\n // { id: 'products', slug: 'products', name: 'Products', description: 'Product catalog page' },\n];\n\n/**\n * Prompts the user for project configuration\n * Pre-fills values from CLI options when provided\n */\nexport async function promptProjectConfig(\n projectName: string,\n options: CreateOptions,\n): Promise<ProjectConfig | null> {\n // Build questions based on what options are missing\n const questions: prompts.PromptObject[] = [];\n\n // Page template selection (only if there are optional templates)\n if (OPTIONAL_PAGE_TEMPLATES.length > 0) {\n questions.push({\n type: \"multiselect\",\n name: \"selectedPages\",\n message: \"Select additional page templates to include\",\n instructions:\n \"\\n Space to select, Enter to confirm. Core pages (Messaging, Contacts, CRM) are always included.\",\n choices: OPTIONAL_PAGE_TEMPLATES.map((page) => ({\n title: page.name,\n value: { id: page.id, slug: page.slug, name: page.name },\n description: page.description,\n })),\n });\n }\n\n // CLI profile for .fluidrc\n const existingProfiles = listProfileNames();\n if (existingProfiles.length > 0) {\n const active = getActiveProfile();\n questions.push({\n type: \"select\",\n name: \"profileName\",\n message: \"CLI profile for this project (.fluidrc)\",\n choices: existingProfiles.map((name) => ({\n title: name === active?.name ? `${name} (active)` : name,\n value: name,\n })),\n });\n }\n\n // Install dependencies\n if (!options.skipInstall) {\n questions.push({\n type: \"confirm\",\n name: \"installDeps\",\n message: \"Install dependencies?\",\n initial: true,\n });\n }\n\n // Non-interactive mode: if stdin is not a TTY and there are remaining\n // prompts, return safe defaults instead of hanging on interactive input.\n if (!process.stdin.isTTY && questions.length > 0) {\n return {\n name: projectName,\n installDeps: false,\n selectedPages: [],\n profileName: getActiveProfile()?.name ?? \"\",\n } satisfies ProjectConfig;\n }\n\n // Fast-path: all options provided via CLI flags, no prompts needed\n if (questions.length === 0) {\n return {\n name: projectName,\n installDeps: options.skipInstall ? false : true,\n selectedPages: [],\n profileName: getActiveProfile()?.name ?? \"\",\n } satisfies ProjectConfig;\n }\n\n // Handle Ctrl+C gracefully\n let cancelled = false;\n const response = await prompts(questions, {\n onCancel: () => {\n cancelled = true;\n return false;\n },\n });\n\n if (cancelled) {\n return null;\n }\n\n // Parse selected pages\n const selectedPages: readonly SelectedPageTemplate[] =\n response.selectedPages ?? [];\n\n return {\n name: projectName,\n installDeps: options.skipInstall ? false : (response.installDeps ?? true),\n selectedPages,\n profileName:\n (response.profileName as string | undefined) ??\n getActiveProfile()?.name ??\n \"\",\n } satisfies ProjectConfig;\n}\n","import type { CliError } from \"@fluid-app/fluid-cli\";\nimport { readdir, readFile, stat, mkdir, writeFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join, dirname, relative } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport Handlebars from \"handlebars\";\nimport type { TemplateVariables } from \"../types.js\";\nimport { type Result, success, failure } from \"@fluid-app/fluid-cli\";\n\nconst _currentFile = fileURLToPath(import.meta.url);\nconst _currentDir = dirname(_currentFile);\n\n/**\n * Find the package root by walking up from the current directory to the nearest package.json.\n * Works whether running from dist/ (bundled) or src/utils/ (tsx dev mode).\n */\nfunction findPackageRoot(): string {\n let dir = _currentDir;\n while (!existsSync(join(dir, \"package.json\"))) {\n const parent = dirname(dir);\n if (parent === dir) throw new Error(\"Could not find package root\");\n dir = parent;\n }\n return dir;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// File system operation error types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Error types for file system operations\n */\nexport const FILE_SYSTEM_ERRORS = {\n directoryNotFound: \"DIRECTORY_NOT_FOUND\",\n fileNotFound: \"FILE_NOT_FOUND\",\n readError: \"READ_ERROR\",\n writeError: \"WRITE_ERROR\",\n templateError: \"TEMPLATE_ERROR\",\n} as const;\n\n/**\n * Union type for file system error codes\n */\nexport type FileSystemErrorCode =\n (typeof FILE_SYSTEM_ERRORS)[keyof typeof FILE_SYSTEM_ERRORS];\n\n/**\n * Structured file system error with code for pattern matching\n */\nexport interface FileSystemError extends CliError {\n readonly code: FileSystemErrorCode;\n readonly message: string;\n readonly path?: string;\n readonly cause?: Error;\n}\n\n/**\n * Create a file system error\n */\nfunction createFsError(\n code: FileSystemErrorCode,\n message: string,\n path?: string,\n cause?: Error,\n): FileSystemError {\n return { code, message, path, cause };\n}\n\n/**\n * Paths for the base + overlay template system\n */\nexport interface TemplatePaths {\n /** Path to shared frontend files used by all templates */\n readonly base: string;\n /** Path to template-specific overlay files */\n readonly overlay: string;\n}\n\n/**\n * Gets paths for the base + overlay template system.\n *\n * The create command copies `base` first, then the `overlay` on top.\n * Any overlay file with the same relative path overwrites the base version.\n */\nexport function getTemplatePaths(templateName: string): TemplatePaths {\n const packageRoot = findPackageRoot();\n const templatesDir = join(packageRoot, \"templates\");\n return {\n base: join(templatesDir, \"base\"),\n overlay: join(templatesDir, templateName),\n };\n}\n\n/**\n * Gets all files in a directory recursively\n */\nasync function getFiles(dir: string, baseDir: string = dir): Promise<string[]> {\n const entries = await readdir(dir, { withFileTypes: true });\n const files: string[] = [];\n\n for (const entry of entries) {\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n files.push(...(await getFiles(fullPath, baseDir)));\n } else {\n // Return relative path from baseDir\n files.push(fullPath.slice(baseDir.length + 1));\n }\n }\n\n return files;\n}\n\n/**\n * Processes a template file with Handlebars\n * Files ending in .template have the extension removed and content processed\n * Other files are copied as-is\n */\nfunction processTemplate(\n content: string,\n variables: TemplateVariables,\n isTemplate: boolean,\n filePath?: string,\n): string {\n if (!isTemplate) {\n return content;\n }\n\n try {\n const template = Handlebars.compile(content);\n return template(variables);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(\n `Template processing failed${filePath ? ` for ${filePath}` : \"\"}: ${message}`,\n );\n }\n}\n\n/**\n * Gets the output filename for a template file\n * Removes .template extension if present\n */\ninterface TemplateSkillFile {\n readonly relativePath: string;\n readonly content: string;\n}\n\nasync function getSharedTemplateSkillFiles(): Promise<TemplateSkillFile[]> {\n const packageRoot = findFluidCliPackageRoot();\n const skillsRoot = join(packageRoot, \"template-skills\");\n const files = await getFiles(skillsRoot);\n\n return Promise.all(\n files.map(async (file) => ({\n relativePath: join(\"skills\", file),\n content: await readFile(join(skillsRoot, file), \"utf-8\"),\n })),\n );\n}\n\nfunction findFluidCliPackageRoot(): string {\n const workspacePackageRoot = join(findPackageRoot(), \"..\", \"core\");\n if (existsSync(join(workspacePackageRoot, \"template-skills\"))) {\n return workspacePackageRoot;\n }\n\n let dir = dirname(fileURLToPath(import.meta.resolve(\"@fluid-app/fluid-cli\")));\n while (!existsSync(join(dir, \"package.json\"))) {\n const parent = dirname(dir);\n if (parent === dir)\n throw new Error(\"Could not find Fluid CLI package root\");\n dir = parent;\n }\n return dir;\n}\n\nasync function writeOutputFiles(\n targetPath: string,\n outputFiles: readonly string[],\n content: string,\n): Promise<void> {\n for (const outputFile of outputFiles) {\n const destPath = join(targetPath, outputFile);\n const destDir = dirname(destPath);\n await mkdir(destDir, { recursive: true });\n await writeFile(destPath, content, \"utf-8\");\n }\n}\n\nfunction getOutputFilenames(filename: string): string[] {\n const outputFilename = getOutputFilename(filename);\n const normalized = outputFilename.replace(/\\\\/g, \"/\");\n\n if (normalized === \"AGENTS.md\") return [\"AGENTS.md\", \"CLAUDE.md\"];\n\n if (normalized.startsWith(\"skills/\")) {\n return [join(\".agents\", outputFilename), join(\".claude\", outputFilename)];\n }\n\n return [outputFilename];\n}\n\nfunction getOutputFilename(filename: string): string {\n if (filename.endsWith(\".template\")) {\n return filename.slice(0, -\".template\".length);\n }\n return filename;\n}\n\n/**\n * Copies a template directory to the target directory\n * Processes .template files with Handlebars\n */\nexport async function copyTemplate(\n templatePath: string,\n targetPath: string,\n variables: TemplateVariables,\n): Promise<void> {\n const files = await getFiles(templatePath);\n\n for (const file of files) {\n const sourcePath = join(templatePath, file);\n const isTemplate = file.endsWith(\".template\");\n const outputFiles = getOutputFilenames(file);\n\n // Read source file\n const content = await readFile(sourcePath, \"utf-8\");\n\n // Process and write\n const processed = processTemplate(\n content,\n variables,\n isTemplate,\n sourcePath,\n );\n\n for (const outputFile of outputFiles) {\n const destPath = join(targetPath, outputFile);\n const destDir = dirname(destPath);\n await mkdir(destDir, { recursive: true });\n await writeFile(destPath, processed, \"utf-8\");\n }\n }\n\n for (const skillFile of await getSharedTemplateSkillFiles()) {\n await writeOutputFiles(\n targetPath,\n getOutputFilenames(skillFile.relativePath),\n skillFile.content,\n );\n }\n}\n\n/**\n * Checks if a directory exists\n */\nexport async function directoryExists(path: string): Promise<boolean> {\n try {\n const stats = await stat(path);\n return stats.isDirectory();\n } catch {\n return false;\n }\n}\n\n/**\n * Checks if a file exists\n */\nexport async function fileExists(path: string): Promise<boolean> {\n try {\n const stats = await stat(path);\n return stats.isFile();\n } catch {\n return false;\n }\n}\n\n/**\n * Checks if a path exists (file or directory)\n */\nexport async function pathExists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Creates a directory\n */\nexport async function createDirectory(path: string): Promise<void> {\n await mkdir(path, { recursive: true });\n}\n\n/**\n * Reads the SDK version from the workspace package.json\n * Falls back to ^0.1.0 if not found\n */\nexport async function getSdkVersion(): Promise<string> {\n try {\n // Try to read from workspace\n // CLI lives at packages/cli/portal/, SDK at packages/portal/sdk/\n const packageRoot = findPackageRoot();\n const packagesRoot = join(packageRoot, \"..\", \"..\");\n const sdkPackagePath = join(packagesRoot, \"portal\", \"sdk\", \"package.json\");\n\n const content = await readFile(sdkPackagePath, \"utf-8\");\n const pkg = JSON.parse(content) as { version?: string };\n return `^${pkg.version ?? \"0.1.0\"}`;\n } catch {\n // Fallback for when running outside the workspace\n return \"^0.1.0\";\n }\n}\n\n/**\n * Builds a pnpm link: specifier for local scaffolds.\n *\n * link: keeps the dependency pointed at the workspace package source instead of\n * packing only package.json \"files\" entries like file: does. That lets Vite's\n * development export resolve the SDK source and its workspace dependencies.\n */\nexport function getLocalPackageLinkVersion(\n targetPath: string,\n packagePath: string,\n): string {\n const linkPath = (relative(targetPath, packagePath) || \".\").replace(\n /\\\\/g,\n \"/\",\n );\n return `link:${linkPath}`;\n}\n\n/**\n * Reads the CLI core version from the workspace package.json.\n * Falls back to ^0.1.0 if not found.\n *\n * This is separate from getSdkVersion because the CLI and portal SDK\n * are versioned independently.\n */\nexport async function getCliVersion(): Promise<string> {\n try {\n // CLI portal lives at packages/cli/portal/, CLI core at packages/cli/core/\n const packageRoot = findPackageRoot();\n const cliCorePath = join(packageRoot, \"..\", \"core\", \"package.json\");\n\n const content = await readFile(cliCorePath, \"utf-8\");\n const pkg = JSON.parse(content) as { version?: string };\n return `^${pkg.version ?? \"0.1.0\"}`;\n } catch {\n return \"^0.1.0\";\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Result-based variants for type-safe error handling\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Read a file's content with Result-based error handling\n */\nexport async function readFileSafe(\n path: string,\n): Promise<Result<string, FileSystemError>> {\n try {\n const content = await readFile(path, \"utf-8\");\n return success(content);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n return failure(\n createFsError(\n FILE_SYSTEM_ERRORS.readError,\n `Failed to read file: ${path}`,\n path,\n error,\n ),\n );\n }\n}\n\n/**\n * Write content to a file with Result-based error handling\n */\nexport async function writeFileSafe(\n path: string,\n content: string,\n): Promise<Result<void, FileSystemError>> {\n try {\n await writeFile(path, content, \"utf-8\");\n return success(undefined);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n return failure(\n createFsError(\n FILE_SYSTEM_ERRORS.writeError,\n `Failed to write file: ${path}`,\n path,\n error,\n ),\n );\n }\n}\n\n/**\n * Create a directory with Result-based error handling\n */\nexport async function createDirectorySafe(\n path: string,\n): Promise<Result<void, FileSystemError>> {\n try {\n await mkdir(path, { recursive: true });\n return success(undefined);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n return failure(\n createFsError(\n FILE_SYSTEM_ERRORS.writeError,\n `Failed to create directory: ${path}`,\n path,\n error,\n ),\n );\n }\n}\n\n/**\n * Copy a template directory with Result-based error handling\n */\nexport async function copyTemplateSafe(\n templatePath: string,\n targetPath: string,\n variables: Readonly<TemplateVariables>,\n): Promise<Result<void, FileSystemError>> {\n try {\n const files = await getFiles(templatePath);\n\n for (const file of files) {\n const sourcePath = join(templatePath, file);\n const isTemplateFile = file.endsWith(\".template\");\n const outputFiles = getOutputFilenames(file);\n\n // Read source file\n const content = await readFile(sourcePath, \"utf-8\");\n\n // Process and write\n const processed = processTemplate(\n content,\n variables,\n isTemplateFile,\n sourcePath,\n );\n\n for (const outputFile of outputFiles) {\n const destPath = join(targetPath, outputFile);\n const destDir = dirname(destPath);\n await mkdir(destDir, { recursive: true });\n await writeFile(destPath, processed, \"utf-8\");\n }\n }\n\n for (const skillFile of await getSharedTemplateSkillFiles()) {\n await writeOutputFiles(\n targetPath,\n getOutputFilenames(skillFile.relativePath),\n skillFile.content,\n );\n }\n\n return success(undefined);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n return failure(\n createFsError(\n FILE_SYSTEM_ERRORS.templateError,\n `Failed to copy template from ${templatePath} to ${targetPath}`,\n templatePath,\n error,\n ),\n );\n }\n}\n\n/**\n * Get SDK version with Result-based error handling\n * Unlike getSdkVersion, this returns an error instead of a fallback\n */\nexport async function getSdkVersionSafe(): Promise<\n Result<string, FileSystemError>\n> {\n try {\n // CLI lives at packages/cli/portal/, SDK at packages/portal/sdk/\n const packageRoot = findPackageRoot();\n const packagesRoot = join(packageRoot, \"..\", \"..\");\n const sdkPackagePath = join(packagesRoot, \"portal\", \"sdk\", \"package.json\");\n\n const content = await readFile(sdkPackagePath, \"utf-8\");\n const pkg = JSON.parse(content) as { version?: string };\n const version = pkg.version;\n\n if (version === undefined) {\n return failure(\n createFsError(\n FILE_SYSTEM_ERRORS.readError,\n \"SDK package.json does not contain a version field\",\n sdkPackagePath,\n ),\n );\n }\n\n return success(`^${version}`);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n return failure(\n createFsError(\n FILE_SYSTEM_ERRORS.fileNotFound,\n \"Could not find SDK package.json\",\n undefined,\n error,\n ),\n );\n }\n}\n","import { execa } from \"execa\";\n\n/**\n * Returns the install command for pnpm\n */\nexport function getInstallCommand(): string {\n return \"pnpm install\";\n}\n\n/**\n * Returns the run command for pnpm\n */\nexport function getRunCommand(script: string): string {\n return `pnpm run ${script}`;\n}\n\n/**\n * Runs a pnpm command in the specified directory\n */\nexport async function runPackageManager(\n args: string[],\n cwd: string,\n): Promise<void> {\n await execa(\"pnpm\", args, {\n cwd,\n stdio: \"inherit\",\n });\n}\n\n/**\n * Installs dependencies using pnpm\n */\nexport async function installDependencies(cwd: string): Promise<void> {\n await runPackageManager([\"install\"], cwd);\n}\n","import { Command } from \"commander\";\nimport type { PluginContext } from \"@fluid-app/fluid-cli\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { join, dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { copyFile } from \"node:fs/promises\";\nimport type { CreateOptions } from \"../types.js\";\nimport { promptProjectConfig } from \"../utils/prompts.js\";\nimport {\n getTemplatePaths,\n copyTemplate,\n directoryExists,\n createDirectory,\n getSdkVersion,\n getCliVersion,\n fileExists,\n getLocalPackageLinkVersion,\n} from \"../utils/file-system.js\";\nimport {\n installDependencies,\n getRunCommand,\n} from \"../utils/package-manager.js\";\n\nexport const createCommand: Command = new Command(\"create\")\n .description(\"Create a new Fluid portal application\")\n .argument(\"<app-name>\", \"Name of the application to create\")\n .option(\"--skip-install\", \"Skip dependency installation\")\n .option(\n \"-o, --output-dir <dir>\",\n \"Directory to create the project in (defaults to cwd)\",\n )\n .option(\n \"--local\",\n \"Use local monorepo packages via file: links (for development testing)\",\n )\n .action(async (appName: string, options: CreateOptions) => {\n try {\n console.log();\n console.log(chalk.bold(\"Creating a new Fluid portal application\"));\n console.log();\n\n // Validate app name\n if (!/^[a-z0-9-]+$/.test(appName)) {\n console.error(\n chalk.red(\n \"Error: App name must contain only lowercase letters, numbers, and hyphens\",\n ),\n );\n process.exit(1);\n }\n\n // Check if directory already exists\n const targetPath = join(\n resolve(options.outputDir ?? process.cwd()),\n appName,\n );\n if (await directoryExists(targetPath)) {\n console.error(\n chalk.red(`Error: Directory \"${appName}\" already exists`),\n );\n process.exit(1);\n }\n\n // Prompt for configuration\n const config = await promptProjectConfig(appName, options);\n if (!config) {\n console.log();\n console.log(chalk.yellow(\"Cancelled\"));\n process.exit(0);\n }\n\n console.log();\n\n // Get template paths (base + overlay)\n const templatePaths = getTemplatePaths(\"starter\");\n if (!(await directoryExists(templatePaths.base))) {\n console.error(chalk.red(\"Error: Base template not found\"));\n process.exit(1);\n }\n if (!(await directoryExists(templatePaths.overlay))) {\n console.error(chalk.red(\"Error: Starter template not found\"));\n process.exit(1);\n }\n\n // Get package versions (SDK and CLI are versioned independently)\n let sdkVersion: string;\n let localCoreVersion: string | undefined;\n const cliVersion = await getCliVersion();\n const isLocal = !!options.local;\n\n if (isLocal) {\n // Resolve relative file: paths so the generated project is portable\n // within the same monorepo clone (works regardless of absolute location)\n const currentDir = dirname(fileURLToPath(import.meta.url));\n const packageRoot = join(currentDir, \"..\", \"..\");\n const packagesRoot = join(packageRoot, \"..\", \"..\");\n const sdkPath = join(packagesRoot, \"portal\", \"sdk\");\n const corePath = join(packagesRoot, \"portal\", \"core\");\n\n if (\n !(await directoryExists(sdkPath)) ||\n !(await directoryExists(corePath))\n ) {\n console.error(\n chalk.red(\n \"Error: --local requires running from within the fluid-mono monorepo\\n\" +\n \" Could not find packages/portal/sdk or packages/portal/core\",\n ),\n );\n process.exit(1);\n }\n\n sdkVersion = getLocalPackageLinkVersion(targetPath, sdkPath);\n localCoreVersion = getLocalPackageLinkVersion(targetPath, corePath);\n console.log(chalk.cyan(\" Using local packages (--local mode)\"));\n } else {\n sdkVersion = await getSdkVersion();\n }\n\n // Create project directory\n const spinner = ora(\"Creating project directory...\").start();\n try {\n await createDirectory(targetPath);\n spinner.succeed(\"Created project directory\");\n } catch (error) {\n spinner.fail(\"Failed to create project directory\");\n throw error;\n }\n\n // Copy base template first, then overlay template-specific files on top\n const templateVariables = {\n projectName: config.name,\n sdkVersion,\n localCoreVersion,\n cliVersion,\n selectedPages: config.selectedPages,\n hasSelectedPages: config.selectedPages.length > 0,\n profileName: config.profileName,\n };\n\n spinner.start(\"Copying template files...\");\n try {\n await copyTemplate(templatePaths.base, targetPath, templateVariables);\n await copyTemplate(\n templatePaths.overlay,\n targetPath,\n templateVariables,\n );\n\n // Copy .env.example → .env so dotenv works out of the box\n const envExamplePath = join(targetPath, \".env.example\");\n if (await fileExists(envExamplePath)) {\n await copyFile(envExamplePath, join(targetPath, \".env\"));\n }\n\n spinner.succeed(\"Copied template files\");\n } catch (error) {\n spinner.fail(\"Failed to copy template files\");\n throw error;\n }\n\n // Install dependencies\n if (config.installDeps) {\n spinner.start(\"Installing dependencies with pnpm...\");\n try {\n await installDependencies(targetPath);\n spinner.succeed(\"Installed dependencies\");\n } catch {\n spinner.fail(\"Failed to install dependencies\");\n console.log();\n console.log(\n chalk.yellow(\"You can try installing dependencies manually:\"),\n );\n console.log(chalk.cyan(` cd ${appName}`));\n console.log(chalk.cyan(\" pnpm install\"));\n }\n }\n\n // Print success message\n console.log();\n console.log(\n chalk.green.bold(\"Success!\") + ` Created ${chalk.cyan(appName)}`,\n );\n console.log();\n console.log(\"Next steps:\");\n console.log();\n const cdPath = options.outputDir ? targetPath : appName;\n console.log(chalk.cyan(` cd ${cdPath}`));\n if (!config.installDeps) {\n console.log(chalk.cyan(\" pnpm install\"));\n }\n console.log(chalk.cyan(` ${getRunCommand(\"dev\")}`));\n console.log();\n console.log(\n \"Then open \" +\n chalk.cyan(\"http://localhost:5173\") +\n \" in your browser.\",\n );\n console.log(\n chalk.dim(\n \" (port may differ if 5173 is in use — check the dev server output)\",\n ),\n );\n console.log();\n if (!config.profileName) {\n console.log(\n chalk.yellow(\n \" Run \" +\n chalk.cyan(\"fluid login\") +\n \" and update \" +\n chalk.cyan(\".fluidrc\") +\n \" with your profile name.\",\n ),\n );\n console.log();\n }\n console.log(\n \"Run \" +\n chalk.cyan(\"pnpm pull\") +\n \" and edit \" +\n chalk.cyan(\"portal/\") +\n \" JSON to customize your portal definition.\",\n );\n console.log();\n } catch (error) {\n console.log();\n console.log(\n chalk.red(\"Error:\") +\n \" \" +\n (error instanceof Error ? error.message : String(error)),\n );\n console.log();\n process.exit(1);\n }\n });\n\nexport function registerCreateCommand(ctx: PluginContext): void {\n ctx.program.addCommand(createCommand);\n}\n","/**\n * `fluid portal dev` command\n *\n * Starts the Vite development server with the portal dev plugin,\n * which intercepts manifest API requests and serves content from\n * the local `portal/` directory.\n *\n * If no `portal/` directory exists, prompts the user to run `fluid portal pull`\n * or auto-pulls if they are logged in.\n */\n\nimport { Command } from \"commander\";\nimport type { PluginContext } from \"@fluid-app/fluid-cli\";\nimport chalk from \"chalk\";\nimport { execa } from \"execa\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { DevOptions } from \"../types.js\";\n\nconst PORTAL_DIR = \"portal\";\n\n/**\n * Check if the portal directory exists and has content files.\n * Returns true if at minimum `portal/definition.json` exists.\n */\nfunction hasPortalContent(cwd: string): boolean {\n return existsSync(join(cwd, PORTAL_DIR, \"definition.json\"));\n}\n\n/**\n * Attempt to auto-pull portal content by invoking the pull command's action.\n * Falls back to a helpful error message if pull is not possible.\n */\nasync function autoPull(cwd: string): Promise<boolean> {\n console.log();\n console.log(\n chalk.yellow(\"No portal/ directory found.\") +\n \" Attempting to pull content...\",\n );\n console.log();\n\n try {\n // Dynamically import the pull command to avoid circular deps at module level.\n // Auth is handled internally by the pull command via stored CLI credentials\n // (getAuthToken / getActiveProfile), so no explicit token args are needed.\n // Note: the pull command may call process.exit(1) on failure (e.g. auth\n // errors), which will terminate the process rather than throwing. Use\n // --skip-pull to bypass this if auto-pull causes issues.\n const { pullCommand } = await import(\"./pull.js\");\n\n await pullCommand.parseAsync([], { from: \"user\" });\n\n // Verify content was pulled\n return hasPortalContent(cwd);\n } catch (err) {\n console.log();\n console.log(\n chalk.red(\"Auto-pull failed: \") +\n (err instanceof Error ? err.message : String(err)),\n );\n console.log();\n console.log(\n \"Run \" +\n chalk.cyan(\"fluid portal pull\") +\n \" manually to set up local content.\",\n );\n console.log();\n return false;\n }\n}\n\nexport const devCommand: Command = new Command(\"dev\")\n .description(\"Start the development server with local portal content serving\")\n .option(\"-p, --port <port>\", \"Port to run the dev server on\", \"5173\")\n .option(\"--host\", \"Expose the dev server to the network\")\n .option(\"--skip-pull\", \"Skip auto-pull if portal/ directory is missing\")\n .action(async (options: DevOptions & { skipPull?: boolean }) => {\n const cwd = process.cwd();\n\n // Check if we're in a Fluid project\n const packageJsonPath = join(cwd, \"package.json\");\n if (!existsSync(packageJsonPath)) {\n console.error(\n chalk.red(\"Error: No package.json found in current directory\"),\n );\n console.error(\n chalk.yellow(\"Make sure you're in a Fluid project directory\"),\n );\n process.exit(1);\n }\n\n // Check for vite.config\n const viteConfigPath = join(cwd, \"vite.config.ts\");\n if (!existsSync(viteConfigPath)) {\n console.error(chalk.red(\"Error: No vite.config.ts found\"));\n console.error(\n chalk.yellow(\"This command must be run from a Fluid project directory\"),\n );\n process.exit(1);\n }\n\n // ── Auto-pull check ────────────────────────────────────────────────\n if (!hasPortalContent(cwd) && !options.skipPull) {\n const pulled = await autoPull(cwd);\n if (!pulled) {\n console.error(\n chalk.red(\"Cannot start dev server without portal content.\"),\n );\n console.error(\n chalk.yellow(\n \"Run \" +\n chalk.cyan(\"fluid portal pull\") +\n \" to download content first.\",\n ),\n );\n process.exit(1);\n }\n }\n\n if (hasPortalContent(cwd)) {\n console.log();\n console.log(\n chalk.green(\"Portal dev mode: \") +\n \"local content from \" +\n chalk.cyan(\"portal/\") +\n \" will be served\",\n );\n console.log(\n chalk.gray(\n \" Manifest requests intercepted at /api/fluid_os/definitions/active\",\n ),\n );\n console.log(\n chalk.gray(\" File changes in portal/ will trigger a page reload\"),\n );\n }\n\n // Build vite args\n const viteArgs = [\"vite\"];\n if (options.port) {\n viteArgs.push(\"--port\", String(options.port));\n }\n if (options.host) {\n viteArgs.push(\"--host\");\n }\n\n console.log();\n console.log(chalk.bold(\"Starting development server...\"));\n console.log();\n\n try {\n await execa(\"pnpm\", viteArgs, {\n cwd,\n stdio: \"inherit\",\n });\n } catch (error) {\n // execa v8 sets `signal` (not `code`) when a process is killed by a signal\n const execaError = error as { signal?: string };\n if (execaError.signal === \"SIGINT\") {\n return;\n }\n console.error(chalk.red(\"Development server exited with an error\"));\n process.exit(1);\n }\n });\n\nexport function registerDevCommand(ctx: PluginContext): void {\n ctx.program.addCommand(devCommand);\n}\n","import { execa } from \"execa\";\nimport fs from \"fs-extra\";\nimport { createRequire } from \"node:module\";\nimport path from \"node:path\";\nimport { type Result, success, failure } from \"@fluid-app/fluid-cli\";\n\nconst CONFIG_CANDIDATES = [\n \"src/widgets.config.ts\",\n \"src/portal.config.ts\",\n \"portal.config.ts\",\n] as const;\nconst SOURCE_PACKAGE_EXTRACT_FILENAME = \"extract-widget-packages.ts\";\nconst SOURCE_PACKAGE_OUTPUT_FILENAME = \"source-widget-packages.json\";\nconst SOURCE_PACKAGE_OUTPUT_SENTINEL = \"fluid-widget-source-packages:v1\";\nconst require = createRequire(import.meta.url);\nconst TSX_CLI_PATH = require.resolve(\"tsx/cli\");\n\nexport interface WidgetSourceConfig {\n readonly path: string;\n readonly relativePath: string;\n}\n\nexport interface WidgetSourceConfigLoadError {\n readonly code: \"CONFIG_LOAD_FAILED\" | \"INVALID_FORMAT\";\n readonly message: string;\n readonly details?: string;\n}\n\nexport async function resolvePortalWidgetSourceConfig(\n projectDir: string,\n): Promise<WidgetSourceConfig | undefined> {\n for (const relativePath of CONFIG_CANDIDATES) {\n const candidate = path.join(projectDir, relativePath);\n if (await fs.pathExists(candidate)) {\n return { path: candidate, relativePath };\n }\n }\n\n return undefined;\n}\n\nexport async function loadSourceWidgetPackages(\n projectDir: string,\n): Promise<Result<unknown[], WidgetSourceConfigLoadError>> {\n const config = await resolvePortalWidgetSourceConfig(projectDir);\n if (!config) return success([]);\n\n let tempDir: string | undefined;\n\n try {\n tempDir = await createTempDirectory(projectDir);\n const extractFile = path.join(tempDir, SOURCE_PACKAGE_EXTRACT_FILENAME);\n const outputFile = path.join(tempDir, SOURCE_PACKAGE_OUTPUT_FILENAME);\n\n await fs.writeFile(\n extractFile,\n createSourcePackageExtractorScript({\n projectDir,\n configPath: config.path,\n }),\n { encoding: \"utf-8\", flag: \"wx\" },\n );\n\n await execa(process.execPath, [TSX_CLI_PATH, extractFile, outputFile], {\n cwd: projectDir,\n stdio: \"pipe\",\n env: { ...process.env, NODE_ENV: \"production\" },\n });\n\n const outputResult = await readSourcePackageExtractorOutput(outputFile);\n if (!outputResult.success) return outputResult;\n\n const parsed = outputResult.value;\n if (parsed.length === 0) return success([]);\n\n return success(parsed);\n } catch (err) {\n const error = err as { stderr?: string; message?: string };\n return failure({\n code: \"CONFIG_LOAD_FAILED\",\n message: `Failed to load widget packages from ${config.relativePath}`,\n details: error.stderr ?? error.message ?? String(err),\n });\n } finally {\n if (tempDir) await fs.remove(tempDir).catch(() => {});\n }\n}\n\nasync function createTempDirectory(projectDir: string): Promise<string> {\n const projectTmpDir = path.join(projectDir, \".fluid\", \"tmp\");\n try {\n await fs.ensureDir(projectTmpDir);\n return await fs.mkdtemp(path.join(projectTmpDir, \"widget-packages-\"));\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(\n `Unable to create project-local temporary directory at ${projectTmpDir}: ${message}`,\n );\n }\n}\n\nasync function readSourcePackageExtractorOutput(\n outputFile: string,\n): Promise<Result<unknown[], WidgetSourceConfigLoadError>> {\n let output: string;\n try {\n output = await fs.readFile(outputFile, \"utf-8\");\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return failure({\n code: \"CONFIG_LOAD_FAILED\",\n message: \"Widget package extractor did not write an output file\",\n details: message,\n });\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(output);\n } catch {\n return failure({\n code: \"INVALID_FORMAT\",\n message: \"Failed to parse widget package output file as JSON\",\n details: `Output was: ${output.slice(0, 200)}`,\n });\n }\n\n if (!isRecord(parsed) || parsed.sentinel !== SOURCE_PACKAGE_OUTPUT_SENTINEL) {\n return failure({\n code: \"INVALID_FORMAT\",\n message: \"Widget package extractor output file had an invalid sentinel\",\n });\n }\n\n if (!Array.isArray(parsed.data)) {\n return failure({\n code: \"INVALID_FORMAT\",\n message: \"Extracted widget package output is not an array\",\n details: `Expected an array, got: ${typeof parsed.data}`,\n });\n }\n\n return success(parsed.data);\n}\n\nfunction createSourcePackageExtractorScript(options: {\n readonly projectDir: string;\n readonly configPath: string;\n}): string {\n return `\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { createServer, normalizePath } from \"vite\";\n\nconst SOURCE_PACKAGE_MARKER = \"__fluidSourceWidgetPackage\";\nconst OUTPUT_SENTINEL = ${JSON.stringify(SOURCE_PACKAGE_OUTPUT_SENTINEL)};\nconst projectRoot = ${JSON.stringify(options.projectDir)};\nconst widgetConfigPath = ${JSON.stringify(options.configPath)};\nconst outputPath = process.argv[2];\nif (!outputPath) throw new Error(\"Missing widget package extractor output path.\");\n\nfunction toViteModuleId(modulePath) {\n const relativePath = path.relative(projectRoot, modulePath);\n if (!relativePath.startsWith(\"..\") && !path.isAbsolute(relativePath)) {\n return \"/\" + normalizePath(relativePath);\n }\n return normalizePath(modulePath);\n}\n\nconst server = await createServer({\n root: projectRoot,\n mode: \"production\",\n server: { middlewareMode: true },\n appType: \"custom\",\n logLevel: \"error\",\n clearScreen: false,\n resolve: {\n conditions: [\"fluid-widget-authoring\"],\n },\n ssr: {\n noExternal: [\"@fluid-app/portal-sdk\"],\n resolve: {\n conditions: [\"fluid-widget-authoring\"],\n },\n },\n});\n\ntry {\n const widgetConfig = await server.ssrLoadModule(toViteModuleId(widgetConfigPath));\n\n function isSourceWidgetPackage(value) {\n return Boolean(value && typeof value === \"object\" && value[SOURCE_PACKAGE_MARKER] === true);\n }\n\n function collectSourceWidgetPackages(mod) {\n const candidates = [\n mod.widgetPackage,\n ...(Array.isArray(mod.widgetPackages) ? mod.widgetPackages : []),\n mod.default,\n ];\n const byPackageId = new Map();\n for (const candidate of candidates) {\n if (!isSourceWidgetPackage(candidate)) continue;\n if (!byPackageId.has(candidate.packageId)) byPackageId.set(candidate.packageId, candidate);\n }\n return Array.from(byPackageId.values());\n }\n\n function serializeWidget(widget) {\n if (!widget || typeof widget !== \"object\" || Array.isArray(widget)) {\n return widget;\n }\n const { component, ...metadata } = widget;\n return metadata;\n }\n\n function serializePackage(sourcePackage) {\n return {\n manifestVersion: sourcePackage.manifestVersion,\n scope: sourcePackage.scope,\n packageStableId: sourcePackage.packageStableId,\n packageId: sourcePackage.packageId,\n packageType: sourcePackage.packageType,\n version: sourcePackage.version,\n cssUrls: sourcePackage.cssUrls,\n widgets: Array.isArray(sourcePackage.widgets)\n ? sourcePackage.widgets.map(serializeWidget)\n : sourcePackage.widgets,\n };\n }\n\n await fs.writeFile(\n outputPath,\n JSON.stringify({\n sentinel: OUTPUT_SENTINEL,\n data: collectSourceWidgetPackages(widgetConfig).map(serializePackage),\n }),\n \"utf-8\",\n );\n} finally {\n await server.close();\n}\n`;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","/**\n * Manifest extraction utility\n *\n * Extracts serializable widget manifest metadata from portal.config.ts\n * by writing a minimal wrapper script that imports customWidgets plus\n * source widget package exports and serializes the result to a temp output\n * file, then running it with tsx.\n *\n * Strips the `component` field (not serializable) from each manifest.\n *\n * Writes a temp script, runs it with tsx, and parses JSON output from the\n * output file. The wrapper loads config modules through Vite SSR so project\n * aliases and Vite-compatible module resolution are honored.\n */\n\nimport { execa } from \"execa\";\nimport fs from \"fs-extra\";\nimport { createRequire } from \"node:module\";\nimport path from \"path\";\nimport { type Result, success, failure } from \"@fluid-app/fluid-cli\";\nimport { resolvePortalWidgetSourceConfig } from \"./widget-package-config.js\";\n\n/**\n * Serializable widget manifest — the JSON-safe subset of WidgetManifest.\n * Mirrors SerializableManifest from portal-core without the package dependency.\n */\nexport interface ExtractedManifest {\n readonly manifestVersion: number;\n readonly type: string;\n readonly displayName: string;\n readonly description: string;\n readonly icon: string;\n readonly category: string;\n readonly propertySchema: Record<string, unknown>;\n readonly defaultProps: Record<string, unknown>;\n readonly [key: string]: unknown;\n}\n\nexport interface ManifestExtractionError {\n readonly code: \"EXTRACTION_FAILED\" | \"INVALID_FORMAT\";\n readonly message: string;\n readonly details?: string;\n}\n\nconst EXTRACT_FILENAME = \"extract-manifests.ts\";\nconst EXTRACT_OUTPUT_FILENAME = \"manifests.json\";\nconst EXTRACT_OUTPUT_SENTINEL = \"fluid-widget-manifests:v1\";\nconst require = createRequire(import.meta.url);\nconst TSX_CLI_PATH = require.resolve(\"tsx/cli\");\n\n/**\n * Extract serializable widget manifests from a project's portal.config.ts.\n *\n * Writes a temp wrapper script, runs it with tsx, and parses the temp JSON\n * output file. The temp files are always cleaned up.\n *\n * Returns an empty array if no customWidgets or source package exports exist.\n *\n * Supported static export shapes are intentionally simple so the CLI can avoid\n * executing unrelated portal configs: named `export const|let|var customWidgets`,\n * `widgetPackage`, or `widgetPackages`; direct `export default\n * defineWidgetPackage(...)`; or `export default <identifier>` where that\n * identifier is initialized with `defineWidgetPackage(...)` in the same file.\n * Re-export-only and computed export shapes are not detected by this layer.\n *\n * @param projectDir - The project root directory containing src/portal.config.ts\n */\nexport async function extractManifests(\n projectDir: string,\n): Promise<Result<ExtractedManifest[], ManifestExtractionError>> {\n let tempDir: string | undefined;\n\n try {\n const config = await resolvePortalWidgetSourceConfig(projectDir);\n if (!config) {\n return success([]);\n }\n\n const configSource = await fs.readFile(config.path, \"utf-8\");\n const configExports = readStaticWidgetExports(configSource);\n const legacyPortalConfigPath = path.join(\n projectDir,\n \"src\",\n \"portal.config.ts\",\n );\n const shouldReadLegacyPortalConfig =\n path.resolve(config.path) !== path.resolve(legacyPortalConfigPath) &&\n (await fs.pathExists(legacyPortalConfigPath));\n const legacyPortalConfigExports = shouldReadLegacyPortalConfig\n ? readStaticWidgetExports(\n await fs.readFile(legacyPortalConfigPath, \"utf-8\"),\n )\n : undefined;\n const legacyCustomWidgetsConfigPath =\n legacyPortalConfigExports?.hasCustomWidgets\n ? legacyPortalConfigPath\n : undefined;\n\n if (\n !configExports.hasCustomWidgets &&\n !configExports.hasSourceWidgetPackages &&\n !legacyCustomWidgetsConfigPath\n ) {\n return success([]);\n }\n\n tempDir = await createTempDirectory(projectDir);\n const extractFile = path.join(tempDir, EXTRACT_FILENAME);\n const outputFile = path.join(tempDir, EXTRACT_OUTPUT_FILENAME);\n\n // Write wrapper script that imports manifests and strips component field\n const wrapperScript = createManifestExtractorScript({\n projectDir,\n widgetConfigPath: config.path,\n legacyCustomWidgetsConfigPath,\n });\n await fs.writeFile(extractFile, wrapperScript, {\n encoding: \"utf-8\",\n flag: \"wx\",\n });\n\n await execa(process.execPath, [TSX_CLI_PATH, extractFile, outputFile], {\n cwd: projectDir,\n stdio: \"pipe\",\n env: { ...process.env, NODE_ENV: \"production\" },\n });\n\n const outputResult = await readManifestExtractorOutput(outputFile);\n if (!outputResult.success) return outputResult;\n\n const parsed = outputResult.value;\n if (parsed.length === 0) {\n return success([]);\n }\n\n const validated = parsed.filter(\n (m): m is ExtractedManifest =>\n typeof m === \"object\" &&\n m !== null &&\n typeof (m as Record<string, unknown>).type === \"string\" &&\n typeof (m as Record<string, unknown>).displayName === \"string\",\n );\n return success(validated);\n } catch (err) {\n const error = err as { stderr?: string; message?: string };\n return failure({\n code: \"EXTRACTION_FAILED\",\n message:\n \"Failed to extract widget manifests from portal widget source config\",\n details: error.stderr ?? error.message ?? String(err),\n });\n } finally {\n if (tempDir) await fs.remove(tempDir).catch(() => {});\n }\n}\n\ninterface StaticWidgetExports {\n readonly hasCustomWidgets: boolean;\n readonly hasSourceWidgetPackages: boolean;\n}\n\nfunction readStaticWidgetExports(source: string): StaticWidgetExports {\n // Strip comments so the regex doesn't match commented-out exports\n const strippedSource = source\n .replace(/\\/\\/[^\\n]*/g, \"\")\n .replace(/\\/\\*[\\s\\S]*?\\*\\//g, \"\");\n\n const defaultExportMatch = /export\\s+default\\s+([A-Za-z_$][\\w$]*)\\b/.exec(\n strippedSource,\n );\n const widgetPackageDefinitionNames = new Set(\n Array.from(\n strippedSource.matchAll(\n /\\b(?:const|let|var)\\s+([A-Za-z_$][\\w$]*)(?:\\s*:[^=]+)?\\s*=\\s*defineWidgetPackage\\s*\\(/g,\n ),\n (match) => match[1],\n ),\n );\n const hasDefaultWidgetPackageExport =\n /export\\s+default\\s+defineWidgetPackage\\s*\\(/.test(strippedSource) ||\n (defaultExportMatch !== null &&\n widgetPackageDefinitionNames.has(defaultExportMatch[1]));\n\n return {\n hasCustomWidgets: /export\\s+(?:const|let|var)\\s+customWidgets\\b/.test(\n strippedSource,\n ),\n hasSourceWidgetPackages:\n /export\\s+(?:const|let|var)\\s+widgetPackage\\b/.test(strippedSource) ||\n /export\\s+(?:const|let|var)\\s+widgetPackages\\b/.test(strippedSource) ||\n hasDefaultWidgetPackageExport,\n };\n}\n\nasync function createTempDirectory(projectDir: string): Promise<string> {\n const projectTmpDir = path.join(projectDir, \".fluid\", \"tmp\");\n try {\n await fs.ensureDir(projectTmpDir);\n return await fs.mkdtemp(path.join(projectTmpDir, \"manifests-\"));\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(\n `Unable to create project-local temporary directory at ${projectTmpDir}: ${message}`,\n );\n }\n}\n\nasync function readManifestExtractorOutput(\n outputFile: string,\n): Promise<Result<unknown[], ManifestExtractionError>> {\n let output: string;\n try {\n output = await fs.readFile(outputFile, \"utf-8\");\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return failure({\n code: \"EXTRACTION_FAILED\",\n message: \"Manifest extractor did not write an output file\",\n details: message,\n });\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(output);\n } catch {\n return failure({\n code: \"INVALID_FORMAT\",\n message: \"Failed to parse manifest output file as JSON\",\n details: `Output was: ${output.slice(0, 200)}`,\n });\n }\n\n if (!isRecord(parsed) || parsed.sentinel !== EXTRACT_OUTPUT_SENTINEL) {\n return failure({\n code: \"INVALID_FORMAT\",\n message: \"Manifest extractor output file had an invalid sentinel\",\n });\n }\n\n if (!Array.isArray(parsed.data)) {\n return failure({\n code: \"INVALID_FORMAT\",\n message: \"extracted widget manifests output is not an array\",\n details: `Expected an array, got: ${typeof parsed.data}`,\n });\n }\n\n return success(parsed.data);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction createManifestExtractorScript(options: {\n readonly projectDir: string;\n readonly widgetConfigPath: string;\n readonly legacyCustomWidgetsConfigPath?: string;\n}): string {\n return `\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { createServer, normalizePath } from \"vite\";\nimport {\n isSourceWidgetPackage,\n sourceWidgetPackagesToManifests,\n} from \"@fluid-app/portal-sdk\";\n\nconst OUTPUT_SENTINEL = ${JSON.stringify(EXTRACT_OUTPUT_SENTINEL)};\nconst projectRoot = ${JSON.stringify(options.projectDir)};\nconst widgetConfigPath = ${JSON.stringify(options.widgetConfigPath)};\nconst legacyCustomWidgetsConfigPath = ${JSON.stringify(options.legacyCustomWidgetsConfigPath)};\nconst outputPath = process.argv[2];\nif (!outputPath) throw new Error(\"Missing manifest extractor output path.\");\n\nfunction toViteModuleId(modulePath) {\n const relativePath = path.relative(projectRoot, modulePath);\n if (!relativePath.startsWith(\"..\") && !path.isAbsolute(relativePath)) {\n return \"/\" + normalizePath(relativePath);\n }\n return normalizePath(modulePath);\n}\n\nconst server = await createServer({\n root: projectRoot,\n mode: \"production\",\n server: { middlewareMode: true },\n appType: \"custom\",\n logLevel: \"error\",\n clearScreen: false,\n});\n\ntry {\n const portalConfig = await server.ssrLoadModule(toViteModuleId(widgetConfigPath));\n const legacyPortalConfig = legacyCustomWidgetsConfigPath\n ? await server.ssrLoadModule(toViteModuleId(legacyCustomWidgetsConfigPath))\n : {};\n\n const sourcePackages = [];\n const seenSourcePackageIds = new Set();\n for (const candidate of [\n portalConfig.widgetPackage,\n ...(Array.isArray(portalConfig.widgetPackages) ? portalConfig.widgetPackages : []),\n portalConfig.default,\n ]) {\n if (!isSourceWidgetPackage(candidate)) continue;\n if (seenSourcePackageIds.has(candidate.packageId)) continue;\n seenSourcePackageIds.add(candidate.packageId);\n sourcePackages.push(candidate);\n }\n const manifests = [\n ...(Array.isArray(portalConfig.customWidgets) ? portalConfig.customWidgets : []),\n ...(Array.isArray(legacyPortalConfig.customWidgets) ? legacyPortalConfig.customWidgets : []),\n ...sourceWidgetPackagesToManifests(sourcePackages),\n ];\n const serializable = manifests.map(({ component, ...rest }) => rest);\n await fs.writeFile(\n outputPath,\n JSON.stringify({ sentinel: OUTPUT_SENTINEL, data: serializable }),\n \"utf-8\",\n );\n} finally {\n await server.close();\n}\n`;\n}\n","import { Command } from \"commander\";\nimport type { PluginContext } from \"@fluid-app/fluid-cli\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { execa } from \"execa\";\nimport { existsSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { BuildOptions } from \"../types.js\";\nimport { extractManifests } from \"../utils/extract-manifests.js\";\n\nexport const buildCommand: Command = new Command(\"build\")\n .description(\"Build the application for production\")\n .option(\"-o, --out-dir <dir>\", \"Output directory\", \"dist\")\n .action(async (options: BuildOptions) => {\n const cwd = process.cwd();\n\n // Check if we're in a Fluid project\n const packageJsonPath = join(cwd, \"package.json\");\n if (!existsSync(packageJsonPath)) {\n console.error(\n chalk.red(\"Error: No package.json found in current directory\"),\n );\n console.error(\n chalk.yellow(\"Make sure you're in a Fluid project directory\"),\n );\n process.exit(1);\n }\n\n // Check for vite.config\n const viteConfigPath = join(cwd, \"vite.config.ts\");\n if (!existsSync(viteConfigPath)) {\n console.error(chalk.red(\"Error: No vite.config.ts found\"));\n console.error(\n chalk.yellow(\"This command must be run from a Fluid project directory\"),\n );\n process.exit(1);\n }\n\n console.log();\n console.log(chalk.bold(\"Building for production...\"));\n console.log();\n\n const spinner = ora(\"Building...\").start();\n\n try {\n // Run the project's build script\n await execa(\"pnpm\", [\"run\", \"build\"], {\n cwd,\n stdio: \"pipe\",\n });\n\n spinner.succeed(\"Build completed\");\n\n // Extract widget manifests and write to build output.\n // The manifest plugin emits an empty __manifests__.json to the Vite outDir.\n // We overwrite it with real data. Check both common outDir layouts:\n // - \"dist/public\" (monorepo portal)\n // - \"dist\" (starter template, Vite default)\n const manifestSpinner = ora(\"Extracting widget manifests...\").start();\n const outDir = options.outDir ?? \"dist\";\n const manifestResult = await extractManifests(cwd);\n\n // Find where the empty __manifests__.json was emitted by the manifest plugin\n const candidatePaths = [\n join(cwd, outDir, \"__manifests__.json\"),\n join(cwd, outDir, \"public\", \"__manifests__.json\"),\n ];\n const manifestPath = candidatePaths.find((p) => existsSync(p));\n\n if (manifestResult.success) {\n if (manifestResult.value.length === 0) {\n manifestSpinner.info(\"No custom widgets found\");\n } else if (!manifestPath) {\n manifestSpinner.warn(\n `__manifests__.json not found in build output — skipping manifest write`,\n );\n } else {\n writeFileSync(manifestPath, JSON.stringify(manifestResult.value));\n manifestSpinner.succeed(\n `Extracted ${manifestResult.value.length} widget manifest(s)`,\n );\n }\n } else {\n manifestSpinner.warn(\n `Manifest extraction failed: ${manifestResult.error.message}`,\n );\n }\n\n console.log();\n console.log(`Output written to ${chalk.cyan(outDir)}/`);\n console.log();\n console.log(\"To preview the build locally:\");\n console.log(chalk.cyan(\" pnpm vite preview\"));\n console.log();\n } catch (error) {\n spinner.fail(\"Build failed\");\n const execaError = error as { stderr?: string };\n if (execaError.stderr) {\n console.error(execaError.stderr);\n }\n process.exit(1);\n }\n });\n\nexport function registerBuildCommand(ctx: PluginContext): void {\n ctx.program.addCommand(buildCommand);\n}\n","/**\n * Cross-reference validation and change categorization utilities for the push command.\n *\n * Extracted into a standalone utility so that pure logic can be tested\n * without pulling in CLI dependencies (ora, chalk, prompts, etc.).\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { join, basename } from \"node:path\";\nimport { existsSync, readdirSync } from \"node:fs\";\n\nimport type { PortalMappings } from \"./mappings.js\";\nimport type { SnapshotDiff } from \"./snapshot.js\";\nimport type {\n LocalNavigation,\n LocalNavigationItem,\n LocalProfile,\n} from \"./transform.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/** Categorize changed files by resource type. */\nexport interface CategorizedChanges {\n readonly screens: { new: string[]; changed: string[]; deleted: string[] };\n readonly themes: { new: string[]; changed: string[]; deleted: string[] };\n readonly navigations: { new: string[]; changed: string[]; deleted: string[] };\n readonly profiles: { new: string[]; changed: string[]; deleted: string[] };\n}\n\n/** A validation error found during cross-reference checking. */\nexport interface ValidationError {\n readonly file: string;\n readonly message: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Extract the slug from a file path (e.g., \"screens/home.json\" -> \"home\").\n */\nexport function slugFromPath(filePath: string): string {\n return basename(filePath, \".json\");\n}\n\n/**\n * Extract the resource type directory from a file path (e.g., \"screens/home.json\" -> \"screens\").\n */\nfunction resourceTypeFromPath(\n filePath: string,\n): \"screens\" | \"themes\" | \"navigations\" | \"profiles\" | null {\n const dir = filePath.split(\"/\")[0];\n if (\n dir === \"screens\" ||\n dir === \"themes\" ||\n dir === \"navigations\" ||\n dir === \"profiles\"\n ) {\n return dir;\n }\n return null;\n}\n\n/**\n * Read and parse a JSON file from the portal directory.\n */\nasync function readPortalFile<T>(\n portalDir: string,\n relativePath: string,\n): Promise<T> {\n const filePath = join(portalDir, relativePath);\n const content = await readFile(filePath, \"utf-8\");\n return JSON.parse(content) as T;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Change categorization\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Categorize a snapshot diff into resource-type-specific change lists.\n */\nexport function categorizeChanges(diff: SnapshotDiff): CategorizedChanges {\n const result: CategorizedChanges = {\n screens: { new: [], changed: [], deleted: [] },\n themes: { new: [], changed: [], deleted: [] },\n navigations: { new: [], changed: [], deleted: [] },\n profiles: { new: [], changed: [], deleted: [] },\n };\n\n for (const file of diff.new) {\n const type = resourceTypeFromPath(file);\n if (type) result[type].new.push(file);\n }\n for (const file of diff.changed) {\n const type = resourceTypeFromPath(file);\n if (type) result[type].changed.push(file);\n }\n for (const file of diff.deleted) {\n const type = resourceTypeFromPath(file);\n if (type) result[type].deleted.push(file);\n }\n\n return result;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Cross-reference validation\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Validate that all cross-references between local portal files are valid.\n *\n * Checks:\n * - Navigation items' \"screen\" slugs reference existing screen files or mappings\n * - Profile \"navigation\" and \"mobile_navigation\" slugs reference existing nav files or mappings\n * - Profile \"themes\" slugs reference existing theme files or mappings\n */\nexport async function validateCrossReferences(\n portalDir: string,\n mappings: PortalMappings,\n changes: CategorizedChanges,\n): Promise<ValidationError[]> {\n const errors: ValidationError[] = [];\n\n // Build sets of valid slugs (existing mappings + local files on disk)\n const validScreenSlugs = buildValidSlugsSet(portalDir, \"screens\", mappings);\n const validNavSlugs = buildValidSlugsSet(portalDir, \"navigations\", mappings);\n const validThemeSlugs = buildValidSlugsSet(portalDir, \"themes\", mappings);\n\n // Remove deleted resource slugs from valid sets\n for (const file of changes.screens.deleted) {\n validScreenSlugs.delete(slugFromPath(file));\n }\n for (const file of changes.navigations.deleted) {\n validNavSlugs.delete(slugFromPath(file));\n }\n for (const file of changes.themes.deleted) {\n validThemeSlugs.delete(slugFromPath(file));\n }\n\n // Validate navigation files (new + changed)\n const navFilesToCheck = [\n ...changes.navigations.new,\n ...changes.navigations.changed,\n ];\n for (const file of navFilesToCheck) {\n try {\n const nav = await readPortalFile<LocalNavigation>(portalDir, file);\n validateNavigationItems(\n nav.navigation_items,\n file,\n validScreenSlugs,\n errors,\n );\n } catch {\n errors.push({ file, message: \"Failed to read navigation file\" });\n }\n }\n\n // Validate profile files (new + changed)\n const profileFilesToCheck = [\n ...changes.profiles.new,\n ...changes.profiles.changed,\n ];\n for (const file of profileFilesToCheck) {\n try {\n const profile = await readPortalFile<LocalProfile>(portalDir, file);\n\n if (profile.navigation && !validNavSlugs.has(profile.navigation)) {\n errors.push({\n file,\n message: `References navigation \"${profile.navigation}\" which does not exist`,\n });\n }\n\n if (\n profile.mobile_navigation &&\n !validNavSlugs.has(profile.mobile_navigation)\n ) {\n errors.push({\n file,\n message: `References mobile_navigation \"${profile.mobile_navigation}\" which does not exist`,\n });\n }\n\n for (const themeSlug of profile.themes) {\n if (!validThemeSlugs.has(themeSlug)) {\n errors.push({\n file,\n message: `References theme \"${themeSlug}\" which does not exist`,\n });\n }\n }\n } catch {\n errors.push({ file, message: \"Failed to read profile file\" });\n }\n }\n\n return errors;\n}\n\n/**\n * Build a set of valid slugs for a resource type by combining\n * existing mapping slugs with local file slugs on disk.\n */\nfunction buildValidSlugsSet(\n portalDir: string,\n resourceType: \"screens\" | \"themes\" | \"navigations\" | \"profiles\",\n mappings: PortalMappings,\n): Set<string> {\n const slugs = new Set<string>();\n\n // Add all slugs from mappings\n for (const slug of Object.keys(mappings[resourceType])) {\n slugs.add(slug);\n }\n\n // Add slugs from local files on disk\n const dir = join(portalDir, resourceType);\n if (existsSync(dir)) {\n try {\n const entries = readdirSync(dir);\n for (const entry of entries) {\n if (entry.endsWith(\".json\")) {\n slugs.add(basename(entry, \".json\"));\n }\n }\n } catch {\n // Directory doesn't exist or can't be read — skip\n }\n }\n\n return slugs;\n}\n\n/**\n * Recursively validate navigation item screen references.\n */\nfunction validateNavigationItems(\n items: LocalNavigationItem[],\n file: string,\n validScreenSlugs: Set<string>,\n errors: ValidationError[],\n): void {\n for (const item of items) {\n if (item.screen && !validScreenSlugs.has(item.screen)) {\n errors.push({\n file,\n message: `Navigation item \"${item.label ?? \"(unlabeled)\"}\" references screen \"${item.screen}\" which does not exist`,\n });\n }\n if (item.children && item.children.length > 0) {\n validateNavigationItems(item.children, file, validScreenSlugs, errors);\n }\n }\n}\n","/**\n * `fluid portal push` command\n *\n * Pushes local portal content changes to the Fluid OS API.\n * Detects changes since the last pull/push via snapshot diffing,\n * validates cross-references, and pushes resources in dependency order.\n */\n\nimport { Command } from \"commander\";\nimport type { PluginContext } from \"@fluid-app/fluid-cli\";\nimport { getAuthToken, getActiveProfile } from \"@fluid-app/fluid-cli\";\nimport { createFetchClient } from \"@fluid-app/fluidos-api-client\";\nimport type { FetchClient, components } from \"@fluid-app/fluidos-api-client\";\nimport { fluidOs } from \"@fluid-app/fluidos-api-client\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { join } from \"node:path\";\nimport { readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport prompts from \"prompts\";\n\nimport {\n readMappings,\n writeMappings,\n updateMapping,\n removeMapping,\n resolveSlugToId,\n} from \"../utils/mappings.js\";\nimport type { PortalMappings } from \"../utils/mappings.js\";\nimport {\n readSnapshot,\n diffAgainstSnapshot,\n writeSnapshot,\n computeFileHash,\n} from \"../utils/snapshot.js\";\nimport type { SnapshotDiff } from \"../utils/snapshot.js\";\nimport type {\n LocalScreen,\n LocalTheme,\n LocalNavigation,\n LocalNavigationItem,\n LocalProfile,\n} from \"../utils/transform.js\";\nimport {\n categorizeChanges,\n validateCrossReferences,\n slugFromPath,\n} from \"../utils/push-validation.js\";\nimport type { CategorizedChanges } from \"../utils/push-validation.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Types\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Derived from the generated FluidOSNavigationItem but with `id` optional\n * (new items don't have one yet) and `label`/`position` required (needed\n * for create/update payloads).\n */\ntype NavigationSyncItem = Omit<\n components[\"schemas\"][\"FluidOSNavigationItem\"],\n \"id\" | \"label\" | \"position\" | \"children\"\n> & {\n id?: number;\n label: string;\n position: number;\n children?: NavigationSyncItem[];\n parent_id?: number | null;\n};\n\ninterface PushOptions {\n yes?: boolean;\n}\n\n/** Result of a single push operation. */\ninterface PushResult {\n readonly file: string;\n readonly action: \"created\" | \"updated\" | \"deleted\";\n readonly success: boolean;\n readonly error?: string;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Constants\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst PORTAL_DIR = \"portal\";\nconst PORTAL_SYNC_DIR = \".portal-sync\";\n\n/**\n * Convert the local array-form component_tree back to the object\n * the API expects. The pull command normalizes the API object into\n * an array for local convenience; this reverses that transformation.\n */\nfunction toApiComponentTree(\n tree: Record<string, unknown>[],\n): Record<string, unknown> | null {\n if (tree.length === 0) return null;\n if (tree.length === 1) return tree[0]!;\n // Fallback: wrap multiple roots in a container (shouldn't happen in practice)\n return { children: tree };\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Create an authenticated FetchClient using the stored CLI profile.\n */\nfunction createClient(): FetchClient {\n const token = getAuthToken();\n if (!token) {\n const profile = getActiveProfile();\n if (!profile) {\n throw new Error(\n \"Not logged in. Run \" + chalk.cyan(\"fluid login\") + \" first.\",\n );\n }\n throw new Error(\n \"No auth token found for profile \" +\n chalk.cyan(profile.name) +\n \". Run \" +\n chalk.cyan(\"fluid login\") +\n \" to re-authenticate.\",\n );\n }\n\n const baseUrl = process.env[\"FLUID_API_BASE\"] ?? \"https://api.fluid.app\";\n\n return createFetchClient({\n baseUrl,\n getAuthToken: () => token,\n });\n}\n\n/**\n * Extract an enriched error message from a caught value.\n * Includes structured API error data when available.\n */\nfunction enrichedErrorMessage(err: unknown): string {\n let msg = err instanceof Error ? err.message : String(err);\n if (err && typeof err === \"object\" && \"data\" in err) {\n msg += ` — ${JSON.stringify((err as { data: unknown }).data)}`;\n }\n return msg;\n}\n\n/**\n * Read and parse a JSON file from the portal directory.\n */\nasync function readPortalFile<T>(\n portalDir: string,\n relativePath: string,\n): Promise<T> {\n const filePath = join(portalDir, relativePath);\n const content = await readFile(filePath, \"utf-8\");\n return JSON.parse(content) as T;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Resource push functions\n// ─────────────────────────────────────────────────────────────────────────────\n\n/**\n * Push screen changes to the API.\n */\nasync function pushScreens(\n client: FetchClient,\n defId: number,\n portalDir: string,\n changes: CategorizedChanges[\"screens\"],\n mappings: PortalMappings,\n): Promise<{ results: PushResult[]; mappings: PortalMappings }> {\n const results: PushResult[] = [];\n let currentMappings = mappings;\n\n // Create new screens\n for (const file of changes.new) {\n const slug = slugFromPath(file);\n try {\n const local = await readPortalFile<LocalScreen>(portalDir, file);\n const response = await fluidOs.fluid_os_v0_create_fluid_osscreen(\n client,\n defId,\n {\n screen: {\n name: local.name,\n slug,\n component_tree: toApiComponentTree(\n local.component_tree,\n ) as unknown as Record<string, unknown>,\n },\n },\n );\n const newId = response.screen?.id;\n if (newId != null) {\n currentMappings = updateMapping(\n currentMappings,\n \"screens\",\n slug,\n newId,\n );\n }\n results.push({ file, action: \"created\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"created\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n // Update changed screens\n for (const file of changes.changed) {\n const slug = slugFromPath(file);\n const screenId = resolveSlugToId(currentMappings, \"screens\", slug);\n if (screenId == null) {\n results.push({\n file,\n action: \"updated\",\n success: false,\n error: `No mapping found for screen slug \"${slug}\"`,\n });\n return { results, mappings: currentMappings };\n }\n try {\n const local = await readPortalFile<LocalScreen>(portalDir, file);\n await fluidOs.fluid_os_v0_update_fluid_osscreen(client, defId, screenId, {\n screen: {\n name: local.name,\n slug,\n component_tree: toApiComponentTree(\n local.component_tree,\n ) as unknown as Record<string, unknown>,\n },\n });\n results.push({ file, action: \"updated\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"updated\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n // Delete screens\n for (const file of changes.deleted) {\n const slug = slugFromPath(file);\n const screenId = resolveSlugToId(currentMappings, \"screens\", slug);\n if (screenId == null) {\n results.push({\n file,\n action: \"deleted\",\n success: false,\n error: `No mapping found for screen slug \"${slug}\"`,\n });\n return { results, mappings: currentMappings };\n }\n try {\n await fluidOs.fluid_os_v0_delete_fluid_osscreen(client, defId, screenId);\n currentMappings = removeMapping(currentMappings, \"screens\", slug);\n results.push({ file, action: \"deleted\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"deleted\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n return { results, mappings: currentMappings };\n}\n\n/**\n * Push theme changes to the API.\n */\nasync function pushThemes(\n client: FetchClient,\n defId: number,\n portalDir: string,\n changes: CategorizedChanges[\"themes\"],\n mappings: PortalMappings,\n): Promise<{ results: PushResult[]; mappings: PortalMappings }> {\n const results: PushResult[] = [];\n let currentMappings = mappings;\n\n // Create new themes\n for (const file of changes.new) {\n const slug = slugFromPath(file);\n try {\n const local = await readPortalFile<LocalTheme>(portalDir, file);\n const response = await fluidOs.fluid_os_v0_create_fluid_ostheme(\n client,\n defId,\n {\n theme: {\n name: local.name,\n active: local.active,\n config: local.config,\n },\n },\n );\n const newId = response.theme?.id;\n if (newId != null) {\n currentMappings = updateMapping(currentMappings, \"themes\", slug, newId);\n }\n results.push({ file, action: \"created\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"created\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n // Update changed themes\n for (const file of changes.changed) {\n const slug = slugFromPath(file);\n const themeId = resolveSlugToId(currentMappings, \"themes\", slug);\n if (themeId == null) {\n results.push({\n file,\n action: \"updated\",\n success: false,\n error: `No mapping found for theme slug \"${slug}\"`,\n });\n return { results, mappings: currentMappings };\n }\n try {\n const local = await readPortalFile<LocalTheme>(portalDir, file);\n await fluidOs.fluid_os_v0_update_fluid_ostheme(client, defId, themeId, {\n theme: {\n name: local.name,\n active: local.active,\n config: local.config,\n },\n });\n results.push({ file, action: \"updated\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"updated\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n // Delete themes\n for (const file of changes.deleted) {\n const slug = slugFromPath(file);\n const themeId = resolveSlugToId(currentMappings, \"themes\", slug);\n if (themeId == null) {\n results.push({\n file,\n action: \"deleted\",\n success: false,\n error: `No mapping found for theme slug \"${slug}\"`,\n });\n return { results, mappings: currentMappings };\n }\n try {\n await fluidOs.fluid_os_v0_delete_fluid_ostheme(client, defId, themeId);\n currentMappings = removeMapping(currentMappings, \"themes\", slug);\n results.push({ file, action: \"deleted\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"deleted\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n return { results, mappings: currentMappings };\n}\n\n/**\n * Resolve screen slug references to screen IDs in navigation items.\n * Returns a new tree with `screen_id` instead of `screen` slug,\n * shaped to match the FluidOSNavigationItemSyncItem schema.\n */\nfunction resolveNavigationItemScreenIds(\n items: LocalNavigationItem[],\n mappings: PortalMappings,\n): NavigationSyncItem[] {\n return items.map((item) => {\n const screenId = item.screen\n ? (resolveSlugToId(mappings, \"screens\", item.screen) ?? undefined)\n : undefined;\n const result: NavigationSyncItem = {\n ...(item.id ? { id: item.id } : {}),\n label: item.label ?? \"\",\n position: item.position ?? 0,\n icon: item.icon,\n screen_id: screenId ?? null,\n slug: item.slug,\n source: (item.source as \"user\" | \"system\" | \"code\") ?? \"user\",\n parent_id: item.parent_id,\n children: resolveNavigationItemScreenIds(item.children ?? [], mappings),\n };\n return result;\n });\n}\n\n/**\n * Flatten a tree of navigation sync items into a flat list.\n * The API reconciliation logic requires a flat list to correctly\n * compare against the flat server response.\n */\nfunction flattenNavigationItems(\n items: NavigationSyncItem[],\n): NavigationSyncItem[] {\n const flat: NavigationSyncItem[] = [];\n for (const item of items) {\n const { children, ...rest } = item;\n flat.push(rest as NavigationSyncItem);\n if (children && children.length > 0) {\n flat.push(...flattenNavigationItems(children as NavigationSyncItem[]));\n }\n }\n return flat;\n}\n\n/**\n * Push navigation changes to the API.\n */\nasync function pushNavigations(\n client: FetchClient,\n defId: number,\n portalDir: string,\n changes: CategorizedChanges[\"navigations\"],\n mappings: PortalMappings,\n): Promise<{ results: PushResult[]; mappings: PortalMappings }> {\n const results: PushResult[] = [];\n let currentMappings = mappings;\n\n // Create new navigations\n for (const file of changes.new) {\n const slug = slugFromPath(file);\n try {\n const local = await readPortalFile<LocalNavigation>(portalDir, file);\n const response = await fluidOs.fluid_os_v0_create_fluid_osnavigation(\n client,\n defId,\n {\n navigation: {\n name: local.name,\n platform: local.platform as \"web\" | \"mobile\",\n },\n },\n );\n const newId = response.navigation?.id;\n if (newId != null) {\n currentMappings = updateMapping(\n currentMappings,\n \"navigations\",\n slug,\n newId,\n );\n // Create navigation items individually (flatten tree for API).\n // Track local→server ID mapping so child items reference the\n // correct server-assigned parent IDs.\n const resolvedItems = flattenNavigationItems(\n resolveNavigationItemScreenIds(\n local.navigation_items,\n currentMappings,\n ),\n );\n const localToServerId = new Map<number, number>();\n\n for (const item of resolvedItems) {\n const resolvedParentId =\n item.parent_id != null\n ? (localToServerId.get(item.parent_id) ?? item.parent_id)\n : undefined;\n\n const created =\n await fluidOs.fluid_os_v0_create_fluid_osnavigation_item(\n client,\n defId,\n newId,\n {\n navigation_item: {\n label: item.label ?? \"\",\n position: item.position ?? 0,\n icon: item.icon ?? undefined,\n screen_id: item.screen_id ?? undefined,\n slug: item.slug ?? undefined,\n source: item.source ?? undefined,\n parent_id: resolvedParentId,\n },\n },\n );\n\n if (item.id != null && created.navigation_item?.id != null) {\n localToServerId.set(item.id, created.navigation_item.id);\n }\n }\n }\n results.push({ file, action: \"created\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"created\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n // Update changed navigations\n for (const file of changes.changed) {\n const slug = slugFromPath(file);\n const navId = resolveSlugToId(currentMappings, \"navigations\", slug);\n if (navId == null) {\n results.push({\n file,\n action: \"updated\",\n success: false,\n error: `No mapping found for navigation slug \"${slug}\"`,\n });\n return { results, mappings: currentMappings };\n }\n try {\n const local = await readPortalFile<LocalNavigation>(portalDir, file);\n\n // Update navigation metadata\n await fluidOs.fluid_os_v0_update_fluid_osnavigation(\n client,\n defId,\n navId,\n {\n navigation: {\n name: local.name,\n platform: local.platform as \"web\" | \"mobile\",\n },\n },\n );\n\n // Reconcile navigation items via individual CRUD operations.\n // The bulk sync endpoint is unreliable, so we diff local vs server\n // and issue create/update/delete calls like the admin builder does.\n // Flatten the tree since the API returns/expects a flat list.\n const resolvedItems = flattenNavigationItems(\n resolveNavigationItemScreenIds(local.navigation_items, currentMappings),\n );\n\n const serverResponse =\n await fluidOs.fluid_os_v0_list_fluid_osnavigation_items(\n client,\n defId,\n navId,\n );\n const serverItems = serverResponse.navigation_items ?? [];\n const serverById = new Map(serverItems.map((s) => [s.id, s]));\n const localIds = new Set(\n resolvedItems.filter((i) => i.id).map((i) => i.id),\n );\n\n // Delete server items not in local\n for (const serverItem of serverItems) {\n if (!localIds.has(serverItem.id)) {\n await fluidOs.fluid_os_v0_delete_fluid_osnavigation_item(\n client,\n defId,\n navId,\n serverItem.id,\n );\n }\n }\n\n // Create or update local items.\n // Track local→server ID mapping so newly created child items\n // reference the correct server-assigned parent IDs.\n const localToServerId = new Map<number, number>();\n\n for (const item of resolvedItems) {\n const resolvedParentId =\n item.parent_id != null\n ? (localToServerId.get(item.parent_id) ?? item.parent_id)\n : undefined;\n\n const body = {\n label: item.label,\n position: item.position,\n icon: item.icon ?? undefined,\n screen_id: item.screen_id ?? undefined,\n slug: item.slug ?? undefined,\n source: item.source ?? undefined,\n parent_id: resolvedParentId,\n };\n\n if (item.id && serverById.has(item.id)) {\n // Update existing\n await fluidOs.fluid_os_v0_update_fluid_osnavigation_item(\n client,\n defId,\n navId,\n item.id,\n { navigation_item: body },\n );\n } else {\n // Create new\n const created =\n await fluidOs.fluid_os_v0_create_fluid_osnavigation_item(\n client,\n defId,\n navId,\n {\n navigation_item: {\n ...body,\n label: body.label ?? \"\",\n position: body.position ?? 0,\n },\n },\n );\n\n if (item.id != null && created.navigation_item?.id != null) {\n localToServerId.set(item.id, created.navigation_item.id);\n }\n }\n }\n\n results.push({ file, action: \"updated\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"updated\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n // Delete navigations\n for (const file of changes.deleted) {\n const slug = slugFromPath(file);\n const navId = resolveSlugToId(currentMappings, \"navigations\", slug);\n if (navId == null) {\n results.push({\n file,\n action: \"deleted\",\n success: false,\n error: `No mapping found for navigation slug \"${slug}\"`,\n });\n return { results, mappings: currentMappings };\n }\n try {\n await fluidOs.fluid_os_v0_delete_fluid_osnavigation(client, defId, navId);\n currentMappings = removeMapping(currentMappings, \"navigations\", slug);\n results.push({ file, action: \"deleted\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"deleted\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n return { results, mappings: currentMappings };\n}\n\n/**\n * Push profile changes to the API.\n */\nasync function pushProfiles(\n client: FetchClient,\n defId: number,\n portalDir: string,\n changes: CategorizedChanges[\"profiles\"],\n mappings: PortalMappings,\n): Promise<{ results: PushResult[]; mappings: PortalMappings }> {\n const results: PushResult[] = [];\n let currentMappings = mappings;\n\n // Create new profiles\n for (const file of changes.new) {\n const slug = slugFromPath(file);\n try {\n const local = await readPortalFile<LocalProfile>(portalDir, file);\n const body = resolveProfileBody(local, currentMappings);\n const response = await fluidOs.fluid_os_v0_create_fluid_osprofile(\n client,\n defId,\n {\n profile: body,\n },\n );\n const newId = response.profile?.id;\n if (newId != null) {\n currentMappings = updateMapping(\n currentMappings,\n \"profiles\",\n slug,\n newId,\n );\n }\n results.push({ file, action: \"created\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"created\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n // Update changed profiles\n for (const file of changes.changed) {\n const slug = slugFromPath(file);\n const profileId = resolveSlugToId(currentMappings, \"profiles\", slug);\n if (profileId == null) {\n results.push({\n file,\n action: \"updated\",\n success: false,\n error: `No mapping found for profile slug \"${slug}\"`,\n });\n return { results, mappings: currentMappings };\n }\n try {\n const local = await readPortalFile<LocalProfile>(portalDir, file);\n const body = resolveProfileBody(local, currentMappings);\n await fluidOs.fluid_os_v0_update_fluid_osprofile(\n client,\n defId,\n profileId,\n {\n profile: body,\n },\n );\n results.push({ file, action: \"updated\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"updated\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n // Delete profiles\n for (const file of changes.deleted) {\n const slug = slugFromPath(file);\n const profileId = resolveSlugToId(currentMappings, \"profiles\", slug);\n if (profileId == null) {\n results.push({\n file,\n action: \"deleted\",\n success: false,\n error: `No mapping found for profile slug \"${slug}\"`,\n });\n return { results, mappings: currentMappings };\n }\n try {\n await fluidOs.fluid_os_v0_delete_fluid_osprofile(\n client,\n defId,\n profileId,\n );\n currentMappings = removeMapping(currentMappings, \"profiles\", slug);\n results.push({ file, action: \"deleted\", success: true });\n } catch (err) {\n results.push({\n file,\n action: \"deleted\",\n success: false,\n error: enrichedErrorMessage(err),\n });\n return { results, mappings: currentMappings };\n }\n }\n\n return { results, mappings: currentMappings };\n}\n\n/** Typed profile body for API requests (create and update share the same shape). */\ninterface ProfileBody {\n name: string;\n default?: boolean;\n navigation_id?: number;\n mobile_navigation_id?: number;\n theme_ids?: number[];\n permissions?: {\n countries?: number[];\n ranks?: number[];\n roles?: string[];\n platform?: string[];\n };\n}\n\n/**\n * Resolve profile slug references to API IDs for create/update request body.\n */\nfunction resolveProfileBody(\n local: LocalProfile,\n mappings: PortalMappings,\n): ProfileBody {\n const body: ProfileBody = {\n name: local.name,\n default: local.default,\n permissions: local.permissions,\n };\n\n if (local.navigation) {\n const navId = resolveSlugToId(mappings, \"navigations\", local.navigation);\n if (navId != null) {\n body.navigation_id = navId;\n }\n }\n\n if (local.mobile_navigation) {\n const mobileNavId = resolveSlugToId(\n mappings,\n \"navigations\",\n local.mobile_navigation,\n );\n if (mobileNavId != null) {\n body.mobile_navigation_id = mobileNavId;\n }\n }\n\n const themeIds = local.themes\n .map((slug) => resolveSlugToId(mappings, \"themes\", slug))\n .filter((id): id is number => id != null);\n body.theme_ids = themeIds;\n\n return body;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Print helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction printChangesSummary(diff: SnapshotDiff, definitionName: string): void {\n console.log(\n chalk.blue(\"Changes to push for \") +\n chalk.white.bold(`\"${definitionName}\"`) +\n chalk.blue(\":\"),\n );\n console.log();\n\n if (diff.new.length > 0) {\n console.log(chalk.green(\" New: \") + diff.new.join(\", \"));\n }\n if (diff.changed.length > 0) {\n console.log(chalk.yellow(\" Changed: \") + diff.changed.join(\", \"));\n }\n if (diff.deleted.length > 0) {\n console.log(chalk.red(\" Deleted: \") + diff.deleted.join(\", \"));\n }\n console.log();\n}\n\nfunction printPushReport(results: PushResult[], skippedPhases: string[]): void {\n const succeeded = results.filter((r) => r.success);\n const failed = results.filter((r) => !r.success);\n\n if (succeeded.length > 0) {\n console.log(chalk.green.bold(\"Succeeded:\"));\n for (const r of succeeded) {\n console.log(chalk.green(\" \" + r.action + \": \") + r.file);\n }\n }\n\n if (failed.length > 0) {\n console.log();\n console.log(chalk.red.bold(\"Failed:\"));\n for (const r of failed) {\n console.log(\n chalk.red(\" \" + r.action + \": \") +\n r.file +\n chalk.gray(\" — \" + (r.error ?? \"Unknown error\")),\n );\n }\n }\n\n if (skippedPhases.length > 0) {\n console.log();\n console.log(chalk.yellow.bold(\"Skipped phases:\"));\n for (const phase of skippedPhases) {\n console.log(chalk.yellow(\" \" + phase));\n }\n }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Command\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const pushCommand: Command = new Command(\"push\")\n .description(\"Push local portal content changes to the Fluid OS API\")\n .option(\"--yes\", \"Skip confirmation prompt\")\n .action(async (options: PushOptions) => {\n const cwd = process.cwd();\n const portalDir = join(cwd, PORTAL_DIR);\n const portalSyncDir = join(cwd, PORTAL_SYNC_DIR);\n\n console.log();\n console.log(chalk.blue.bold(\"Fluid Portal Push\"));\n console.log();\n\n // ── Check for portal directory ─────────────────────────────────────\n if (!existsSync(portalDir)) {\n console.log(\n chalk.red(\"Error:\") +\n \" No portal/ directory found. Run \" +\n chalk.cyan(\"fluid portal pull\") +\n \" first.\",\n );\n console.log();\n process.exit(1);\n }\n\n // ── Read snapshot ──────────────────────────────────────────────────\n const snapshot = await readSnapshot(portalSyncDir);\n if (!snapshot) {\n console.log(\n chalk.red(\"Error:\") +\n \" No snapshot found in .portal-sync/. Run \" +\n chalk.cyan(\"fluid portal pull\") +\n \" first.\",\n );\n console.log();\n process.exit(1);\n }\n\n // ── Read mappings ──────────────────────────────────────────────────\n const mappings = await readMappings(portalSyncDir);\n if (!mappings) {\n console.log(\n chalk.red(\"Error:\") +\n \" No mappings found in .portal-sync/. Run \" +\n chalk.cyan(\"fluid portal pull\") +\n \" first.\",\n );\n console.log();\n process.exit(1);\n }\n\n const definitionId = snapshot.definition_id;\n const definitionName = snapshot.definition;\n\n console.log(\n chalk.gray(\"Definition: \") +\n chalk.white(definitionName) +\n chalk.gray(` (ID: ${definitionId})`),\n );\n console.log();\n\n // ── Detect changes ─────────────────────────────────────────────────\n const spinner = ora();\n spinner.start(\"Detecting changes...\");\n\n const diff = await diffAgainstSnapshot(portalDir, snapshot);\n const totalChanges =\n diff.new.length + diff.changed.length + diff.deleted.length;\n\n if (totalChanges === 0) {\n spinner.succeed(\"Nothing to push.\");\n console.log();\n return;\n }\n\n spinner.succeed(`Found ${totalChanges} change(s)`);\n console.log();\n\n // ── Show changes and confirm ───────────────────────────────────────\n printChangesSummary(diff, definitionName);\n\n if (!options.yes) {\n const { confirmed } = await prompts({\n type: \"confirm\",\n name: \"confirmed\",\n message: `Push ${totalChanges} change(s) to Fluid OS?`,\n initial: false,\n });\n\n if (!confirmed) {\n console.log();\n console.log(chalk.gray(\"Push cancelled.\"));\n console.log();\n return;\n }\n console.log();\n }\n\n // ── Categorize changes ─────────────────────────────────────────────\n const changes = categorizeChanges(diff);\n\n // ── Cross-reference validation ─────────────────────────────────────\n spinner.start(\"Validating cross-references...\");\n const validationErrors = await validateCrossReferences(\n portalDir,\n mappings,\n changes,\n );\n\n if (validationErrors.length > 0) {\n spinner.fail(\"Cross-reference validation failed\");\n console.log();\n for (const err of validationErrors) {\n console.log(chalk.red(\" \" + err.file + \": \") + err.message);\n }\n console.log();\n process.exit(1);\n }\n spinner.succeed(\"Cross-references valid\");\n\n // ── Authenticate ───────────────────────────────────────────────────\n spinner.start(\"Authenticating...\");\n\n let client: FetchClient;\n try {\n client = createClient();\n spinner.succeed(\"Authenticated\");\n } catch (err) {\n spinner.fail(\"Authentication failed\");\n console.log();\n console.log(\n chalk.red(\"Error:\") +\n \" \" +\n (err instanceof Error ? err.message : String(err)),\n );\n console.log();\n process.exit(1);\n }\n\n // ── Phase 1: Screens + Themes (parallel) ───────────────────────────\n const allResults: PushResult[] = [];\n const skippedPhases: string[] = [];\n let currentMappings = mappings;\n let aborted = false;\n\n const hasScreenChanges =\n changes.screens.new.length > 0 ||\n changes.screens.changed.length > 0 ||\n changes.screens.deleted.length > 0;\n const hasThemeChanges =\n changes.themes.new.length > 0 ||\n changes.themes.changed.length > 0 ||\n changes.themes.deleted.length > 0;\n\n if (hasScreenChanges || hasThemeChanges) {\n spinner.start(\"Phase 1: Pushing screens and themes...\");\n\n const phase1Tasks: Promise<{\n results: PushResult[];\n mappings: PortalMappings;\n }>[] = [];\n\n if (hasScreenChanges) {\n phase1Tasks.push(\n pushScreens(\n client,\n definitionId,\n portalDir,\n changes.screens,\n currentMappings,\n ),\n );\n }\n if (hasThemeChanges) {\n phase1Tasks.push(\n pushThemes(\n client,\n definitionId,\n portalDir,\n changes.themes,\n currentMappings,\n ),\n );\n }\n\n const phase1Results = await Promise.all(phase1Tasks);\n\n // Merge mappings from both parallel operations\n // Only apply the resource type each operation actually owns\n for (const result of phase1Results) {\n allResults.push(...result.results);\n }\n if (hasScreenChanges) {\n currentMappings = {\n ...currentMappings,\n screens: phase1Results[0]!.mappings.screens,\n };\n }\n if (hasThemeChanges) {\n const idx = hasScreenChanges ? 1 : 0;\n currentMappings = {\n ...currentMappings,\n themes: phase1Results[idx]!.mappings.themes,\n };\n }\n\n const phase1Failed = phase1Results.some((r) =>\n r.results.some((res) => !res.success),\n );\n\n if (phase1Failed) {\n spinner.fail(\"Phase 1 failed\");\n aborted = true;\n skippedPhases.push(\"Phase 2: Navigations\", \"Phase 3: Profiles\");\n } else {\n spinner.succeed(\"Phase 1 complete\");\n }\n }\n\n // ── Phase 2: Navigations ───────────────────────────────────────────\n const hasNavChanges =\n changes.navigations.new.length > 0 ||\n changes.navigations.changed.length > 0 ||\n changes.navigations.deleted.length > 0;\n\n if (!aborted && hasNavChanges) {\n spinner.start(\"Phase 2: Pushing navigations...\");\n\n const navResult = await pushNavigations(\n client,\n definitionId,\n portalDir,\n changes.navigations,\n currentMappings,\n );\n\n allResults.push(...navResult.results);\n currentMappings = {\n ...currentMappings,\n navigations: navResult.mappings.navigations,\n };\n\n const phase2Failed = navResult.results.some((r) => !r.success);\n if (phase2Failed) {\n spinner.fail(\"Phase 2 failed\");\n aborted = true;\n skippedPhases.push(\"Phase 3: Profiles\");\n } else {\n spinner.succeed(\"Phase 2 complete\");\n }\n } else if (aborted && hasNavChanges) {\n // Already marked as skipped above\n }\n\n // ── Phase 3: Profiles ──────────────────────────────────────────────\n const hasProfileChanges =\n changes.profiles.new.length > 0 ||\n changes.profiles.changed.length > 0 ||\n changes.profiles.deleted.length > 0;\n\n if (!aborted && hasProfileChanges) {\n spinner.start(\"Phase 3: Pushing profiles...\");\n\n const profileResult = await pushProfiles(\n client,\n definitionId,\n portalDir,\n changes.profiles,\n currentMappings,\n );\n\n allResults.push(...profileResult.results);\n currentMappings = {\n ...currentMappings,\n profiles: profileResult.mappings.profiles,\n };\n\n const phase3Failed = profileResult.results.some((r) => !r.success);\n if (phase3Failed) {\n spinner.fail(\"Phase 3 failed\");\n } else {\n spinner.succeed(\"Phase 3 complete\");\n }\n }\n\n // ── Update mappings ────────────────────────────────────────────────\n await writeMappings(portalSyncDir, currentMappings);\n\n // ── Update snapshot for successfully pushed files ───────────────────\n const successfulFiles = new Set(\n allResults.filter((r) => r.success).map((r) => r.file),\n );\n\n if (successfulFiles.size > 0) {\n // Only advance snapshot entries for successfully pushed files;\n // leave skipped/failed entries at their original hashes so they\n // show up as changed on the next run.\n const updatedHashes = { ...snapshot.files };\n for (const file of successfulFiles) {\n const fullPath = join(portalDir, file);\n if (existsSync(fullPath)) {\n updatedHashes[file] = await computeFileHash(fullPath);\n } else {\n // deleted file — remove from snapshot\n delete updatedHashes[file];\n }\n }\n await writeSnapshot(portalSyncDir, {\n ...snapshot,\n files: updatedHashes,\n });\n }\n\n // ── Report ─────────────────────────────────────────────────────────\n console.log();\n const allSucceeded = allResults.every((r) => r.success);\n\n if (allSucceeded && !aborted) {\n console.log(chalk.green.bold(\"Push complete!\"));\n } else {\n console.log(chalk.yellow.bold(\"Push completed with issues:\"));\n }\n console.log();\n printPushReport(allResults, skippedPhases);\n console.log();\n });\n\nexport function registerPushCommand(ctx: PluginContext): void {\n ctx.program.addCommand(pushCommand);\n}\n","/**\n * Pure helper functions for widget scaffolding.\n * Extracted from widget-create command for testability.\n */\n\n/**\n * Convert kebab-case name to PascalCase widget type.\n * e.g., \"stock-ticker\" → \"StockTickerWidget\"\n */\nexport function toWidgetType(name: string): string {\n const pascal = name\n .split(\"-\")\n .map((s) => s.charAt(0).toUpperCase() + s.slice(1))\n .join(\"\");\n return pascal.endsWith(\"Widget\") ? pascal : `${pascal}Widget`;\n}\n\n/**\n * Derive the component name from a widget type.\n * Strips the trailing \"Widget\" suffix, but only if the result is non-empty\n * and starts with a letter (not a digit).\n * e.g., \"StockTickerWidget\" → \"StockTicker\"\n */\nexport function toComponentName(widgetType: string): string {\n if (widgetType === \"Widget\") return \"Widget\";\n const stripped = widgetType.replace(/Widget$/, \"\");\n return stripped || widgetType;\n}\n\n/**\n * Convert kebab-case name to a display name.\n * e.g., \"stock-ticker\" → \"Stock Ticker\"\n */\nexport function toDisplayName(name: string): string {\n return name\n .split(\"-\")\n .map((s) => s.charAt(0).toUpperCase() + s.slice(1))\n .join(\" \");\n}\n\n/**\n * Convert kebab-case to camelCase.\n * e.g., \"stock-ticker\" → \"stockTicker\"\n */\nexport function toCamelCase(name: string): string {\n return name.replace(/-./g, (x) => x.charAt(1).toUpperCase());\n}\n\n/**\n * Validate a widget name for scaffold.\n * Must be kebab-case, no trailing/consecutive dashes, no bare \"widget\".\n */\nexport function validateWidgetName(name: string): string | null {\n if (!/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(name)) {\n return \"Widget name must be kebab-case with no trailing or consecutive dashes (e.g., stock-ticker).\";\n }\n if (name === \"widget\") {\n return 'Widget name \"widget\" is reserved. Use a more descriptive name (e.g., custom-widget).';\n }\n return null;\n}\n\n/**\n * Insert an import line after the last import in a source file.\n * Skips if the import already exists (prevents duplicates on re-scaffold).\n * Returns null if no imports exist in the source.\n */\nexport function insertImport(\n source: string,\n importLine: string,\n): string | null {\n // Skip if import already exists\n if (source.includes(importLine)) return source;\n\n // Find the last real import statement (starts at column 0, not inside comments)\n const importPattern = /^import\\s/gm;\n let lastImportIndex = -1;\n let match: RegExpExecArray | null;\n while ((match = importPattern.exec(source)) !== null) {\n lastImportIndex = match.index;\n }\n if (lastImportIndex === -1) return null;\n\n const lineEnd = source.indexOf(\"\\n\", lastImportIndex);\n if (lineEnd === -1) {\n // Last import is on the final line with no trailing newline\n return source + \"\\n\" + importLine + \"\\n\";\n }\n\n return (\n source.slice(0, lineEnd + 1) + importLine + \"\\n\" + source.slice(lineEnd + 1)\n );\n}\n\n/**\n * Insert a manifest reference into the customWidgets array.\n * Preserves developer comments. Skips if already present.\n * Returns null if the array pattern isn't found.\n *\n * Searches for the LAST `export const customWidgets` declaration to skip\n * matches inside JSDoc @example blocks.\n */\nexport function insertIntoCustomWidgets(\n source: string,\n camelName: string,\n): string | null {\n // Find all matches and use the last one (the real declaration, not JSDoc examples).\n // The type annotation may span multiple lines (e.g., `import(\"...\").WidgetManifest[]`),\n // so we use [\\s\\S] to match across newlines between the declaration and the `= [`.\n const pattern =\n /(export const customWidgets(?::[\\s\\S]*?)?\\s*=\\s*)\\[([^\\]]*)\\]/g;\n let lastMatch: RegExpExecArray | null = null;\n let m: RegExpExecArray | null;\n while ((m = pattern.exec(source)) !== null) {\n lastMatch = m;\n }\n\n if (!lastMatch) return null;\n\n const fullMatch = lastMatch[0];\n const declaration = lastMatch[1]!;\n const inner = lastMatch[2]!;\n const matchStart = lastMatch.index;\n\n const lines = inner.split(\"\\n\");\n\n // Collect existing real entries (stripped of commas for comparison)\n const existingEntries: string[] = [];\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed && !trimmed.startsWith(\"//\")) {\n existingEntries.push(trimmed.replace(/,$/, \"\"));\n }\n }\n\n // Skip if already registered\n if (existingEntries.includes(camelName)) {\n return source;\n }\n\n // Preserve comment lines\n const commentLines = lines\n .filter((line) => line.trim().startsWith(\"//\"))\n .map((line) => line.trimEnd());\n\n const commentBlock =\n commentLines.length > 0 ? \"\\n\" + commentLines.join(\"\\n\") : \"\";\n\n // Build entry lines with consistent 2-space indentation\n const allEntries = [...existingEntries, camelName];\n const entryBlock = allEntries.map((e) => ` ${e},`).join(\"\\n\");\n\n const replacement = `${declaration}[${commentBlock}\\n${entryBlock}\\n]`;\n\n return (\n source.slice(0, matchStart) +\n replacement +\n source.slice(matchStart + fullMatch.length)\n );\n}\n","import { Command } from \"commander\";\nimport type { PluginContext } from \"@fluid-app/fluid-cli\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport path from \"node:path\";\nimport type { WidgetCreateOptions } from \"../types.js\";\nimport {\n toWidgetType,\n toComponentName,\n toDisplayName,\n toCamelCase,\n validateWidgetName,\n insertImport,\n insertIntoCustomWidgets,\n} from \"../utils/widget-helpers.js\";\n\nconst createSubcommand = new Command(\"create\")\n .description(\"Scaffold a new custom widget\")\n .argument(\"<name>\", \"Widget name in kebab-case (e.g., stock-ticker)\")\n .option(\n \"-c, --category <category>\",\n \"Widget category for palette grouping\",\n \"components\",\n )\n .action(async (name: string, options: WidgetCreateOptions) => {\n const cwd = process.cwd();\n const widgetDir = path.join(cwd, \"src\", \"widgets\", name);\n\n // Validate name format\n const validationError = validateWidgetName(name);\n if (validationError) {\n console.error(chalk.red(`Error: ${validationError}`));\n process.exit(1);\n }\n\n // Check we're in a Fluid portal project\n if (!fs.existsSync(path.join(cwd, \"src\", \"portal.config.ts\"))) {\n console.error(chalk.red(\"Error: No src/portal.config.ts found.\"));\n console.error(\n chalk.yellow(\"Run this command from a Fluid portal project root.\"),\n );\n process.exit(1);\n }\n\n // Check widget doesn't already exist\n if (fs.existsSync(widgetDir)) {\n console.error(\n chalk.red(\n `Error: Widget directory already exists: src/widgets/${name}`,\n ),\n );\n process.exit(1);\n }\n\n const widgetType = toWidgetType(name);\n const componentName = toComponentName(widgetType);\n const displayName = toDisplayName(name);\n const category = options.category ?? \"components\";\n\n // Create widget directory and write files — clean up on failure\n try {\n await fs.ensureDir(widgetDir);\n\n await fs.writeFile(\n path.join(widgetDir, \"component.tsx\"),\n `interface ${widgetType}Props {\n title?: string;\n}\n\nexport function ${componentName}({ title = \"${displayName}\" }: ${widgetType}Props) {\n return (\n <div className=\"p-4\">\n <h3 className=\"text-lg font-semibold\">{title}</h3>\n <p className=\"text-sm text-gray-500\">\n Edit this widget in src/widgets/${name}/component.tsx\n </p>\n </div>\n );\n}\n`,\n );\n\n await fs.writeFile(\n path.join(widgetDir, \"manifest.ts\"),\n `import type { WidgetManifest } from \"@fluid-app/portal-sdk\";\nimport { ${componentName} } from \"./component\";\n\nexport const manifest: WidgetManifest = {\n manifestVersion: 1,\n type: \"${widgetType}\",\n component: ${componentName},\n displayName: \"${displayName}\",\n description: \"A custom ${displayName.toLowerCase()} widget\",\n icon: \"puzzle-piece\",\n category: \"${category}\",\n propertySchema: {\n widgetType: \"${widgetType}\",\n displayName: \"${displayName}\",\n fields: [{ key: \"title\", label: \"Title\", type: \"text\" }],\n },\n defaultProps: {\n title: \"${displayName}\",\n },\n};\n`,\n );\n\n await fs.writeFile(\n path.join(widgetDir, \"index.ts\"),\n `export { ${componentName} } from \"./component\";\nexport { manifest } from \"./manifest\";\n`,\n );\n } catch (err) {\n await fs.remove(widgetDir).catch(() => {});\n console.error(chalk.red(\"Error: Failed to scaffold widget files.\"));\n console.error(err);\n process.exit(1);\n }\n\n // Auto-register in portal.config.ts\n const configPath = path.join(cwd, \"src\", \"portal.config.ts\");\n const camelName = toCamelCase(name);\n const importLine = `import { manifest as ${camelName} } from \"./widgets/${name}\";`;\n\n const configSource = await fs.readFile(configPath, \"utf-8\");\n\n const withImport = insertImport(configSource, importLine);\n if (withImport === null) {\n console.warn(\n chalk.yellow(\n \"Warning: Could not find import statements in portal.config.ts. \" +\n \"Add the import manually:\",\n ),\n );\n console.warn(chalk.cyan(` ${importLine}`));\n }\n\n let updated = insertIntoCustomWidgets(\n withImport ?? configSource,\n camelName,\n );\n if (updated === null) {\n if (withImport === null) {\n // Neither the import nor the array could be placed — warn and bail\n // to avoid writing a broken config with an undefined identifier\n console.warn(\n chalk.yellow(\n \"Warning: Could not register widget in portal.config.ts. Add manually:\",\n ),\n );\n console.warn(chalk.cyan(` ${importLine}`));\n console.warn(chalk.cyan(` customWidgets: [..., ${camelName}]`));\n } else {\n // Import succeeded but customWidgets array doesn't exist yet — create it\n updated =\n withImport.trimEnd() +\n `\\n\\nexport const customWidgets = [${camelName}];\\n`;\n }\n }\n\n if (updated !== null) {\n await fs.writeFile(configPath, updated, \"utf-8\");\n } else if (withImport !== null) {\n await fs.writeFile(configPath, withImport, \"utf-8\");\n }\n\n console.log();\n console.log(chalk.green(\"Created widget:\") + ` src/widgets/${name}/`);\n console.log(chalk.gray(\" component.tsx — React component\"));\n console.log(chalk.gray(\" manifest.ts — WidgetManifest\"));\n console.log(chalk.gray(\" index.ts — Re-exports\"));\n console.log();\n if (updated !== null) {\n console.log(\n chalk.green(\"Registered\") + ` in ${chalk.cyan(\"src/portal.config.ts\")}`,\n );\n console.log();\n }\n console.log(chalk.yellow(\"Next steps:\"));\n console.log(\n ` 1. Edit the component in ${chalk.cyan(`src/widgets/${name}/component.tsx`)}`,\n );\n console.log(\n ` 2. Customize the manifest fields in ${chalk.cyan(`src/widgets/${name}/manifest.ts`)}`,\n );\n console.log(\n ` 3. Run ${chalk.cyan(\"fluid portal dev\")} to preview in the builder`,\n );\n });\n\nexport const widgetCommand: Command = new Command(\"widget\")\n .description(\"Manage custom portal widgets\")\n .addCommand(createSubcommand);\n\nexport function registerWidgetCommand(ctx: PluginContext): void {\n ctx.program.addCommand(widgetCommand);\n}\n","import fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { createHash } from \"node:crypto\";\n\nexport const WIDGET_PACKAGE_BUILDER_VERSION = \"1\";\n\nexport interface ArtifactMetadata {\n readonly path: string;\n readonly sha256: string;\n readonly bytes: number;\n readonly contentType: string;\n}\n\nexport interface PublishManifestMetadata {\n readonly packageId: string;\n readonly version: string;\n readonly builderVersion: string;\n readonly cliVersion: string;\n readonly runtimeVersion: string;\n readonly manifestHash: string;\n readonly artifacts: readonly ArtifactMetadata[];\n}\n\nconst CONTENT_TYPES: Readonly<Record<string, string>> = {\n \".css\": \"text/css\",\n \".js\": \"application/javascript\",\n \".json\": \"application/json\",\n \".map\": \"application/json\",\n};\nconst CSS_ARTIFACT_PATH_PATTERN = /^[A-Za-z0-9._~-]+\\.css$/;\nconst JS_MAP_ARTIFACT_PATH_PATTERN = /^[A-Za-z0-9._~-]+\\.js\\.map$/;\n\nexport async function computeArtifactMetadata(\n filePath: string,\n baseDir: string,\n): Promise<ArtifactMetadata> {\n const relativePath = toPosixPath(path.relative(baseDir, filePath));\n assertAllowedArtifactPath(relativePath);\n await assertRegularArtifactFile(filePath, relativePath);\n const buffer = await fs.readFile(filePath);\n\n return {\n path: relativePath,\n sha256: sha256(buffer),\n bytes: buffer.byteLength,\n contentType: getArtifactContentType(filePath),\n };\n}\n\nexport async function collectWidgetPackageArtifacts(\n publishDir: string,\n): Promise<ArtifactMetadata[]> {\n const artifactPaths = await findArtifactPaths(publishDir);\n const artifacts = await Promise.all(\n artifactPaths.map((artifactPath) =>\n computeArtifactMetadata(artifactPath, publishDir),\n ),\n );\n\n assertRequiredUploadArtifacts(artifacts);\n\n return artifacts.sort((a, b) => a.path.localeCompare(b.path));\n}\n\nexport function createPublishManifestMetadata(options: {\n readonly packageId: string;\n readonly version: string;\n readonly cliVersion: string;\n readonly runtimeVersion: string;\n readonly manifestContent: string | Buffer;\n readonly artifacts: readonly ArtifactMetadata[];\n readonly builderVersion?: string;\n}): PublishManifestMetadata {\n return {\n packageId: options.packageId,\n version: options.version,\n builderVersion: options.builderVersion ?? WIDGET_PACKAGE_BUILDER_VERSION,\n cliVersion: options.cliVersion,\n runtimeVersion: options.runtimeVersion,\n manifestHash: sha256(options.manifestContent),\n artifacts: options.artifacts,\n };\n}\n\nexport function getArtifactContentType(filePath: string): string {\n const basename = path.basename(filePath);\n if (basename.endsWith(\".js.map\")) {\n return \"application/json\";\n }\n return CONTENT_TYPES[path.extname(filePath)] ?? \"application/octet-stream\";\n}\n\nexport function sha256(content: string | Buffer): string {\n return createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\nexport function isWidgetPackageCssArtifactPath(relativePath: string): boolean {\n return CSS_ARTIFACT_PATH_PATTERN.test(relativePath);\n}\n\nexport function isWidgetPackageJsMapArtifactPath(\n relativePath: string,\n): boolean {\n return JS_MAP_ARTIFACT_PATH_PATTERN.test(relativePath);\n}\n\nasync function assertRegularArtifactFile(\n filePath: string,\n relativePath: string,\n): Promise<void> {\n const stat = await fs.lstat(filePath);\n if (stat.isSymbolicLink()) {\n throw new Error(\n `Widget publish artifact ${JSON.stringify(relativePath)} must be a regular file and must not be a symbolic link.`,\n );\n }\n if (!stat.isFile()) {\n throw new Error(\n `Widget publish artifact ${JSON.stringify(relativePath)} must be a regular file.`,\n );\n }\n}\n\nasync function findArtifactPaths(\n dir: string,\n baseDir: string = dir,\n): Promise<string[]> {\n if (!(await fs.pathExists(dir))) return [];\n\n const entries = await fs.readdir(dir, { withFileTypes: true });\n const paths = await Promise.all(\n entries.map(async (entry) => {\n const entryPath = path.join(dir, entry.name);\n const relativePath = toPosixPath(path.relative(baseDir, entryPath));\n\n if (entry.isSymbolicLink()) {\n throw new Error(\n `Widget publish artifact ${JSON.stringify(relativePath)} must be a regular file and must not be a symbolic link.`,\n );\n }\n\n if (isUploadArtifact(relativePath)) {\n if (!entry.isFile()) {\n throw new Error(\n `Widget publish artifact ${JSON.stringify(relativePath)} must be a regular file.`,\n );\n }\n return [entryPath];\n }\n\n if (entry.isDirectory()) {\n const nestedPaths = await findArtifactPaths(entryPath, baseDir);\n if (nestedPaths.length === 0) {\n throwUnsupportedArtifactPath(`${relativePath}/`);\n }\n return nestedPaths;\n }\n if (isAllowedGeneratedFile(relativePath)) return [];\n throwUnsupportedArtifactPath(relativePath);\n }),\n );\n\n return paths.flat();\n}\n\nfunction assertRequiredUploadArtifacts(\n artifacts: readonly ArtifactMetadata[],\n): void {\n const artifactPaths = new Set(artifacts.map((artifact) => artifact.path));\n for (const requiredPath of [\"widget.js\", \"manifest.json\"] as const) {\n if (artifactPaths.has(requiredPath)) continue;\n throw new Error(\n `Widget package publish output must include regular file ${JSON.stringify(requiredPath)}.`,\n );\n }\n}\n\nfunction assertAllowedArtifactPath(relativePath: string): void {\n if (isUploadArtifact(relativePath) || isAllowedGeneratedFile(relativePath))\n return;\n throwUnsupportedArtifactPath(relativePath);\n}\n\nfunction isUploadArtifact(relativePath: string): boolean {\n return (\n relativePath === \"widget.js\" ||\n relativePath === \"manifest.json\" ||\n isWidgetPackageCssArtifactPath(relativePath) ||\n isWidgetPackageJsMapArtifactPath(relativePath)\n );\n}\n\nfunction isAllowedGeneratedFile(relativePath: string): boolean {\n return (\n isFlatArtifactPath(relativePath) && relativePath === \"publish-manifest.json\"\n );\n}\n\nfunction isFlatArtifactPath(relativePath: string): boolean {\n return (\n relativePath.length > 0 &&\n !relativePath.includes(\"/\") &&\n !relativePath.includes(\"\\\\\")\n );\n}\n\nfunction throwUnsupportedArtifactPath(relativePath: string): never {\n throw new Error(\n `Unsupported widget publish artifact ${JSON.stringify(relativePath)}. ` +\n \"Allowed files are widget.js, manifest.json, top-level [A-Za-z0-9._~-]+.css, top-level [A-Za-z0-9._~-]+.js.map, and publish-manifest.json.\",\n );\n}\n\nfunction toPosixPath(value: string): string {\n return value.split(path.sep).join(\"/\");\n}\n","import { isWidgetPackageCssArtifactPath } from \"./widget-package-artifacts.js\";\n\nconst URL_SAFE_SEGMENT_SOURCE = \"[A-Za-z0-9][A-Za-z0-9_~-]*\";\nconst URL_SAFE_WIDGET_NAME_PATTERN = new RegExp(`^${URL_SAFE_SEGMENT_SOURCE}$`);\nconst URL_SAFE_DOTTED_IDENTIFIER_PATTERN = new RegExp(\n `^${URL_SAFE_SEGMENT_SOURCE}(?:\\\\.${URL_SAFE_SEGMENT_SOURCE})*$`,\n);\nconst SEMVER_CORE_PATTERN = \"(0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)\\\\.(0|[1-9]\\\\d*)\";\nconst SEMVER_PRERELEASE_IDENTIFIER_PATTERN =\n \"(?:0|[1-9]\\\\d*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*)\";\nconst SEMVER_URL_SAFE_PATTERN = new RegExp(\n `^${SEMVER_CORE_PATTERN}(?:-${SEMVER_PRERELEASE_IDENTIFIER_PATTERN}(?:\\\\.${SEMVER_PRERELEASE_IDENTIFIER_PATTERN})*)?$`,\n);\nconst WIDGET_PACKAGE_MANIFEST_VERSION = 1;\nconst DEFAULT_WIDGET_ICON = \"box\";\nconst DEFAULT_WIDGET_CATEGORY = \"components\";\nconst DEFAULT_WIDGET_CONTAINER = \"block\";\nconst DEFAULT_MIN_SDK_VERSION = \"0.0.0\";\n\nexport type WidgetPackageOwnerKind = \"company\" | \"droplet\";\n\nexport type WidgetRuntimeContainer = \"inline\" | \"block\" | \"card\" | \"fullscreen\";\nexport type WidgetRuntimeResizable =\n | boolean\n | \"horizontal\"\n | \"vertical\"\n | \"both\";\n\nexport interface SourceWidgetMetadata {\n readonly name: string;\n readonly displayName?: string;\n readonly description?: string;\n readonly icon?: string;\n readonly category?: string;\n readonly propertySchema?: Record<string, unknown>;\n readonly defaultProps?: Record<string, unknown>;\n readonly container?: unknown;\n readonly minSdkVersion?: string;\n readonly resizable?: unknown;\n}\n\nexport interface SourceWidgetPackageMetadata {\n readonly manifestVersion?: number;\n readonly scope?: string;\n readonly packageStableId?: string;\n readonly packageId: string;\n readonly packageType?: string;\n readonly version: string;\n readonly widgets: readonly SourceWidgetMetadata[];\n readonly cssUrls?: readonly string[];\n}\n\nexport interface WidgetDescriptorMetadata {\n readonly type: string;\n readonly name: string;\n readonly displayName: string;\n readonly description: string;\n readonly icon: string;\n readonly category: string;\n readonly propertySchema: Record<string, unknown>;\n readonly defaultProps: Record<string, unknown>;\n readonly container: WidgetRuntimeContainer;\n readonly minSdkVersion: string;\n readonly resizable: WidgetRuntimeResizable;\n}\n\nexport interface WidgetPackageDescriptorMetadata {\n readonly manifestVersion: 1;\n readonly packageId: string;\n readonly packageType: WidgetPackageOwnerKind;\n readonly version: string;\n readonly remoteEntryUrl: string;\n readonly cssUrls: readonly string[];\n readonly widgets: readonly WidgetDescriptorMetadata[];\n}\n\nexport interface ValidatedWidgetPackageBuild {\n readonly sourcePackage: SourceWidgetPackageMetadata;\n readonly packageKey: string;\n readonly packageId: string;\n readonly owner: WidgetPackageOwnerKind;\n readonly version: string;\n readonly widgets: readonly WidgetDescriptorMetadata[];\n}\n\nexport type WidgetPackageValidationErrorCode =\n | \"NO_SOURCE_PACKAGE\"\n | \"MULTIPLE_SOURCE_PACKAGES\"\n | \"INVALID_SOURCE_PACKAGE\"\n | \"INVALID_WIDGET_METADATA\"\n | \"UNSUPPORTED_OWNER\"\n | \"INVALID_PACKAGE_KEY\"\n | \"INVALID_VERSION\"\n | \"NO_WIDGETS\"\n | \"INVALID_WIDGET_NAME\"\n | \"INVALID_WIDGET_TYPE\"\n | \"DUPLICATE_WIDGET\";\n\nexport interface WidgetPackageValidationError {\n readonly code: WidgetPackageValidationErrorCode;\n readonly message: string;\n readonly path?: string;\n}\n\nexport interface WidgetPackageValidationResult {\n readonly success: boolean;\n readonly value?: ValidatedWidgetPackageBuild;\n readonly errors: readonly WidgetPackageValidationError[];\n}\n\nexport interface ValidateSourceWidgetPackageOptions {\n readonly owner?: WidgetPackageOwnerKind;\n}\n\nexport function validateSingleSourceWidgetPackage(\n sourcePackages: readonly unknown[],\n options: ValidateSourceWidgetPackageOptions = {},\n): WidgetPackageValidationResult {\n if (sourcePackages.length === 0) {\n return validationFailure({\n code: \"NO_SOURCE_PACKAGE\",\n message:\n \"No defineWidgetPackage source package was found. Export widgetPackage, widgetPackages, or a default widget package from src/widgets.config.ts, src/portal.config.ts, or portal.config.ts.\",\n });\n }\n\n if (sourcePackages.length > 1) {\n return validationFailure({\n code: \"MULTIPLE_SOURCE_PACKAGES\",\n message:\n \"Publish/deploy supports exactly one defineWidgetPackage source package. Export one package or split packages into separate builds.\",\n });\n }\n\n const sourcePackageValue = sourcePackages[0];\n if (!sourcePackageValue) {\n return validationFailure({\n code: \"NO_SOURCE_PACKAGE\",\n message: \"No defineWidgetPackage source package was found.\",\n });\n }\n\n const shapeErrors = validateSourcePackageShape(sourcePackageValue);\n if (shapeErrors.length > 0) {\n return { success: false, errors: shapeErrors };\n }\n const sourcePackage = sourcePackageValue as SourceWidgetPackageMetadata;\n\n const errors: WidgetPackageValidationError[] = [];\n const owner = options.owner ?? sourcePackage.packageType;\n if (owner !== \"company\" && owner !== \"droplet\") {\n errors.push({\n code: \"UNSUPPORTED_OWNER\",\n path: \"packageType\",\n message:\n 'Widget package publish/deploy currently supports company and droplet owners. Set packageType to \"company\" or \"droplet\".',\n });\n }\n\n const resolvedOwner = owner === \"droplet\" ? \"droplet\" : \"company\";\n const packageKey = resolvePackageKey(sourcePackage, resolvedOwner);\n const packageKeyPath = readNonEmptyTrimmedString(\n sourcePackage.packageStableId,\n )\n ? \"packageStableId\"\n : \"packageId\";\n if (!isUrlSafeDottedIdentifier(packageKey)) {\n errors.push({\n code: \"INVALID_PACKAGE_KEY\",\n path: packageKeyPath,\n message:\n \"Widget package key must be URL-safe dot-separated text (letters, numbers, '.', '_', '~', and '-' only).\",\n });\n }\n\n if (!isUrlSafeSemver(sourcePackage.version)) {\n errors.push({\n code: \"INVALID_VERSION\",\n path: \"version\",\n message:\n \"Widget package version must be a URL-safe SemVer version without build metadata (for example 1.2.3 or 1.2.3-beta.1).\",\n });\n }\n\n if (sourcePackage.widgets.length === 0) {\n errors.push({\n code: \"NO_WIDGETS\",\n path: \"widgets\",\n message: \"Widget package must include at least one widget.\",\n });\n }\n\n const packageId = `${resolvedOwner}.${packageKey}`;\n const seenNames = new Set<string>();\n const seenTypes = new Set<string>();\n const widgets: WidgetDescriptorMetadata[] = [];\n\n sourcePackage.widgets.forEach((widget, index) => {\n const path = `widgets[${index}]`;\n if (!isUrlSafeWidgetName(widget.name)) {\n errors.push({\n code: \"INVALID_WIDGET_NAME\",\n path: `${path}.name`,\n message:\n \"Widget name must be URL-safe text (letters, numbers, '_', '~', and '-' only) and cannot be empty.\",\n });\n return;\n }\n\n if (seenNames.has(widget.name)) {\n errors.push({\n code: \"DUPLICATE_WIDGET\",\n path: `${path}.name`,\n message: `Duplicate widget name \"${widget.name}\" found in package ${packageKey}.`,\n });\n return;\n }\n seenNames.add(widget.name);\n\n const type = `${packageId}.${widget.name}`;\n if (!isUrlSafeDottedIdentifier(type)) {\n errors.push({\n code: \"INVALID_WIDGET_TYPE\",\n path: `${path}.type`,\n message: `Generated widget type \"${type}\" is not URL-safe.`,\n });\n return;\n }\n\n if (seenTypes.has(type)) {\n errors.push({\n code: \"DUPLICATE_WIDGET\",\n path: `${path}.type`,\n message: `Duplicate generated widget type \"${type}\" found.`,\n });\n return;\n }\n seenTypes.add(type);\n\n widgets.push(sourceWidgetToDescriptor(widget, type));\n });\n\n if (errors.length > 0) return { success: false, errors };\n\n return {\n success: true,\n value: {\n sourcePackage,\n packageKey,\n packageId,\n owner: resolvedOwner,\n version: sourcePackage.version,\n widgets,\n },\n errors: [],\n };\n}\n\nexport function buildWidgetPackageDescriptor(\n validated: ValidatedWidgetPackageBuild,\n options: {\n readonly remoteEntryUrl?: string;\n readonly cssUrls?: readonly string[];\n } = {},\n): WidgetPackageDescriptorMetadata {\n const remoteEntryUrl = options.remoteEntryUrl ?? \"widget.js\";\n validateRuntimeDescriptorUrl(remoteEntryUrl, \"remoteEntryUrl\");\n\n return {\n manifestVersion: WIDGET_PACKAGE_MANIFEST_VERSION,\n packageId: getWidgetPackageDescriptorPackageId(validated),\n packageType: validated.owner,\n version: validated.version,\n remoteEntryUrl,\n cssUrls: mergeCssUrls(validated.sourcePackage.cssUrls, options.cssUrls),\n widgets: validated.widgets,\n };\n}\n\nexport function getWidgetPackageDescriptorPackageId(\n validated: ValidatedWidgetPackageBuild,\n): string {\n return validated.owner === \"droplet\"\n ? validated.packageKey\n : validated.packageId;\n}\n\nfunction sourceWidgetToDescriptor(\n widget: SourceWidgetMetadata,\n type: string,\n): WidgetDescriptorMetadata {\n const displayName = widget.displayName ?? widget.name;\n\n return {\n type,\n name: widget.name,\n displayName,\n description: widget.description ?? `Custom widget ${displayName}`,\n icon: widget.icon ?? DEFAULT_WIDGET_ICON,\n category: widget.category ?? DEFAULT_WIDGET_CATEGORY,\n propertySchema: normalizePropertySchema(widget.propertySchema, type),\n defaultProps: widget.defaultProps ?? {},\n container: normalizeContainer(widget.container),\n minSdkVersion: widget.minSdkVersion ?? DEFAULT_MIN_SDK_VERSION,\n resizable: normalizeResizable(widget.resizable),\n };\n}\n\nfunction validationFailure(\n error: WidgetPackageValidationError,\n): WidgetPackageValidationResult {\n return { success: false, errors: [error] };\n}\n\nfunction validateSourcePackageShape(\n value: unknown,\n): WidgetPackageValidationError[] {\n if (!isRecord(value)) {\n return [\n {\n code: \"INVALID_SOURCE_PACKAGE\",\n message: \"Widget source package must be a JSON object.\",\n },\n ];\n }\n\n const errors: WidgetPackageValidationError[] = [];\n requireStringField(value, \"packageId\", \"packageId\", errors);\n requireStringField(value, \"version\", \"version\", errors);\n validateOptionalStringField(value, \"scope\", \"scope\", errors);\n validateOptionalStringField(\n value,\n \"packageStableId\",\n \"packageStableId\",\n errors,\n );\n validateOptionalStringField(value, \"packageType\", \"packageType\", errors);\n\n if (value.cssUrls !== undefined) {\n if (!Array.isArray(value.cssUrls)) {\n errors.push({\n code: \"INVALID_SOURCE_PACKAGE\",\n path: \"cssUrls\",\n message:\n \"Widget package cssUrls must be an array of strings when present.\",\n });\n } else {\n value.cssUrls.forEach((cssUrl, index) => {\n validateCssUrl(cssUrl, `cssUrls[${index}]`, errors);\n });\n }\n }\n\n if (!Array.isArray(value.widgets)) {\n errors.push({\n code: \"INVALID_SOURCE_PACKAGE\",\n path: \"widgets\",\n message: \"Widget package widgets must be an array.\",\n });\n return errors;\n }\n\n value.widgets.forEach((widget, index) => {\n const widgetPath = `widgets[${index}]`;\n if (!isRecord(widget)) {\n errors.push({\n code: \"INVALID_WIDGET_METADATA\",\n path: widgetPath,\n message: \"Widget metadata must be a JSON object.\",\n });\n return;\n }\n\n requireStringField(widget, \"name\", `${widgetPath}.name`, errors, {\n code: \"INVALID_WIDGET_NAME\",\n message: \"Widget name must be a string and cannot be empty.\",\n });\n validateOptionalStringField(\n widget,\n \"displayName\",\n `${widgetPath}.displayName`,\n errors,\n { requireNonEmpty: true },\n );\n validateOptionalStringField(\n widget,\n \"description\",\n `${widgetPath}.description`,\n errors,\n { requireNonEmpty: true },\n );\n validateOptionalStringField(widget, \"icon\", `${widgetPath}.icon`, errors, {\n requireNonEmpty: true,\n });\n validateOptionalStringField(\n widget,\n \"category\",\n `${widgetPath}.category`,\n errors,\n { requireNonEmpty: true },\n );\n validateOptionalStringField(\n widget,\n \"minSdkVersion\",\n `${widgetPath}.minSdkVersion`,\n errors,\n { requireNonEmpty: true },\n );\n validateOptionalRecordField(\n widget,\n \"propertySchema\",\n `${widgetPath}.propertySchema`,\n errors,\n );\n validateOptionalRecordField(\n widget,\n \"defaultProps\",\n `${widgetPath}.defaultProps`,\n errors,\n );\n });\n\n return errors;\n}\n\nfunction requireStringField(\n record: Record<string, unknown>,\n key: string,\n path: string,\n errors: WidgetPackageValidationError[],\n override?: Pick<WidgetPackageValidationError, \"code\" | \"message\">,\n): void {\n const value = record[key];\n if (typeof value === \"string\" && value.trim().length > 0) return;\n\n errors.push({\n code: override?.code ?? \"INVALID_SOURCE_PACKAGE\",\n path,\n message:\n override?.message ?? `${path} must be a string and cannot be empty.`,\n });\n}\n\nfunction validateOptionalStringField(\n record: Record<string, unknown>,\n key: string,\n path: string,\n errors: WidgetPackageValidationError[],\n options: { readonly requireNonEmpty?: boolean } = {},\n): void {\n const value = record[key];\n if (value === undefined) return;\n if (typeof value === \"string\") {\n if (!options.requireNonEmpty || value.trim().length > 0) return;\n errors.push({\n code: \"INVALID_SOURCE_PACKAGE\",\n path,\n message: `${path} must be a non-empty string when present.`,\n });\n return;\n }\n\n errors.push({\n code: \"INVALID_SOURCE_PACKAGE\",\n path,\n message: `${path} must be a string when present.`,\n });\n}\n\nfunction validateCssUrl(\n value: unknown,\n cssUrlPath: string,\n errors: WidgetPackageValidationError[],\n): void {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n errors.push({\n code: \"INVALID_SOURCE_PACKAGE\",\n path: cssUrlPath,\n message: \"Widget package cssUrls entries must be non-empty strings.\",\n });\n return;\n }\n\n if (!isWidgetPackageCssArtifactPath(value)) {\n errors.push({\n code: \"INVALID_SOURCE_PACKAGE\",\n path: cssUrlPath,\n message:\n \"Widget package cssUrls entries must be top-level generated CSS artifact filenames matching [A-Za-z0-9._~-]+.css. Self-host external CSS or fonts via @font-face in widget CSS so the build can isolate them.\",\n });\n }\n}\n\nfunction validateRuntimeDescriptorUrl(value: string, urlPath: string): void {\n if (value.trim().length === 0) {\n throw new Error(`${urlPath} must be a non-empty string.`);\n }\n\n if (!isValidRuntimeDescriptorUrl(value)) {\n throw new Error(\n `${urlPath} must be an https URL, trusted local http URL, or relative URL.`,\n );\n }\n}\n\nfunction isValidRuntimeDescriptorUrl(value: string): boolean {\n if (value.trim() !== value || containsUnsafeUrlCharacter(value)) return false;\n\n const schemeMatch = /^[a-zA-Z][a-zA-Z\\d+.-]*:/.exec(value);\n if (schemeMatch) {\n let parsedUrl: URL;\n try {\n parsedUrl = new URL(value);\n } catch {\n return false;\n }\n\n return (\n parsedUrl.protocol === \"https:\" || isTrustedLocalHttpUrl(parsedUrl, value)\n );\n }\n\n if (value.slice(0, 2) === \"//\") return false;\n\n try {\n void new URL(value, \"http://localhost\");\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isTrustedLocalHttpUrl(url: URL, rawUrl: string): boolean {\n if (url.protocol !== \"http:\") return false;\n\n const hostname = extractRawHostname(rawUrl).toLowerCase();\n return (\n hostname === \"localhost\" ||\n hostname === \"[::1]\" ||\n hostname === \"::1\" ||\n isLoopbackIpv4Hostname(hostname)\n );\n}\n\nfunction extractRawHostname(rawUrl: string): string {\n const authorityStart = rawUrl.indexOf(\"://\") + 3;\n const authorityEnd = findAuthorityEnd(rawUrl, authorityStart);\n const authority = rawUrl.slice(authorityStart, authorityEnd);\n const hostAndPort = authority.slice(authority.lastIndexOf(\"@\") + 1);\n\n if (hostAndPort.charAt(0) === \"[\") {\n const bracketEnd = hostAndPort.indexOf(\"]\");\n return bracketEnd === -1\n ? hostAndPort\n : hostAndPort.slice(0, bracketEnd + 1);\n }\n\n const portStart = hostAndPort.indexOf(\":\");\n return portStart === -1 ? hostAndPort : hostAndPort.slice(0, portStart);\n}\n\nfunction findAuthorityEnd(rawUrl: string, authorityStart: number): number {\n let authorityEnd = rawUrl.length;\n for (const delimiter of [\"/\", \"?\", \"#\"] as const) {\n const delimiterIndex = rawUrl.indexOf(delimiter, authorityStart);\n if (delimiterIndex !== -1 && delimiterIndex < authorityEnd) {\n authorityEnd = delimiterIndex;\n }\n }\n return authorityEnd;\n}\n\nfunction isLoopbackIpv4Hostname(hostname: string): boolean {\n const octets = hostname.split(\".\");\n if (octets.length !== 4 || octets[0] !== \"127\") return false;\n\n return octets.every(isBoundedIpv4Octet);\n}\n\nfunction isBoundedIpv4Octet(octet: string): boolean {\n if (!/^\\d{1,3}$/.test(octet)) return false;\n if (octet.length > 1 && octet.charAt(0) === \"0\") return false;\n\n const value = Number(octet);\n return value >= 0 && value <= 255;\n}\n\nfunction containsUnsafeUrlCharacter(value: string): boolean {\n for (let index = 0; index < value.length; index += 1) {\n const charCode = value.charCodeAt(index);\n if (charCode <= 0x1f || charCode === 0x7f || charCode === 0x5c) {\n return true;\n }\n }\n\n return false;\n}\n\nfunction validateOptionalRecordField(\n record: Record<string, unknown>,\n key: string,\n path: string,\n errors: WidgetPackageValidationError[],\n): void {\n const value = record[key];\n if (value === undefined || isRecord(value)) return;\n\n errors.push({\n code: \"INVALID_WIDGET_METADATA\",\n path,\n message: `${path} must be a JSON object when present.`,\n });\n}\n\nfunction mergeCssUrls(\n sourceCssUrls: readonly string[] | undefined,\n generatedCssUrls: readonly string[] | undefined,\n): string[] {\n const generatedCssUrlSet = new Set(generatedCssUrls ?? []);\n generatedCssUrls?.forEach((cssUrl, index) => {\n validateGeneratedCssArtifactUrl(cssUrl, `generated cssUrls[${index}]`);\n });\n sourceCssUrls?.forEach((cssUrl, index) => {\n validateGeneratedCssArtifactUrl(cssUrl, `cssUrls[${index}]`);\n if (generatedCssUrlSet.has(cssUrl)) return;\n\n throw new Error(\n `cssUrls[${index}] URL ${JSON.stringify(cssUrl)} must match a generated top-level CSS artifact. ` +\n \"Import the CSS from the widget package bundle or remove it from cssUrls.\",\n );\n });\n\n return Array.from(\n new Set([...(sourceCssUrls ?? []), ...(generatedCssUrls ?? [])]),\n );\n}\n\nfunction validateGeneratedCssArtifactUrl(\n value: string,\n cssUrlPath: string,\n): void {\n if (value.trim().length === 0) {\n throw new Error(`${cssUrlPath} must be a non-empty string.`);\n }\n\n if (!isWidgetPackageCssArtifactPath(value)) {\n throw new Error(\n `${cssUrlPath} must be a top-level generated CSS artifact filename matching [A-Za-z0-9._~-]+.css. Self-host external CSS or fonts via @font-face in widget CSS so the build can isolate them.`,\n );\n }\n}\n\nfunction normalizePropertySchema(\n value: Record<string, unknown> | undefined,\n widgetType: string,\n): Record<string, unknown> {\n return { ...(value ?? {}), widgetType };\n}\n\nfunction normalizeContainer(value: unknown): WidgetRuntimeContainer {\n if (\n value === \"inline\" ||\n value === \"block\" ||\n value === \"card\" ||\n value === \"fullscreen\"\n ) {\n return value;\n }\n\n return DEFAULT_WIDGET_CONTAINER;\n}\n\nfunction normalizeResizable(value: unknown): WidgetRuntimeResizable {\n if (typeof value === \"boolean\") return value;\n if (value === \"horizontal\" || value === \"vertical\" || value === \"both\") {\n return value;\n }\n if (!isRecord(value)) return false;\n\n const horizontal = value.horizontal === true;\n const vertical = value.vertical === true;\n\n if (horizontal && vertical) return \"both\";\n if (horizontal) return \"horizontal\";\n if (vertical) return \"vertical\";\n return false;\n}\n\nfunction resolvePackageKey(\n sourcePackage: SourceWidgetPackageMetadata,\n owner: WidgetPackageOwnerKind,\n): string {\n const packageStableId = readNonEmptyTrimmedString(\n sourcePackage.packageStableId,\n );\n if (packageStableId) {\n return prefixPackageStableIdWithNonOwnerScope(\n packageStableId,\n sourcePackage.scope,\n );\n }\n\n return stripOwnerScopeFromPackageId(\n sourcePackage.packageId,\n sourcePackage.scope,\n owner,\n );\n}\n\nfunction prefixPackageStableIdWithNonOwnerScope(\n packageStableId: string,\n sourceScope: string | undefined,\n): string {\n const sourceScopeText = readNonEmptyTrimmedString(sourceScope);\n if (!sourceScopeText || isWidgetPackageOwnerKind(sourceScopeText)) {\n return packageStableId;\n }\n\n const sourceScopePrefix = `${sourceScopeText}.`;\n if (packageStableId.startsWith(sourceScopePrefix)) return packageStableId;\n return `${sourceScopeText}.${packageStableId}`;\n}\n\nfunction stripOwnerScopeFromPackageId(\n packageId: string,\n sourceScope: string | undefined,\n owner: WidgetPackageOwnerKind,\n): string {\n const ownerPrefix = `${owner}.`;\n if (\n packageId.startsWith(ownerPrefix) &&\n packageId.length > ownerPrefix.length\n ) {\n return packageId.slice(ownerPrefix.length);\n }\n\n const sourceScopeText = readNonEmptyTrimmedString(sourceScope);\n if (\n isWidgetPackageOwnerKind(sourceScopeText) &&\n packageId.startsWith(`${sourceScopeText}.`) &&\n packageId.length > sourceScopeText.length + 1\n ) {\n return packageId.slice(sourceScopeText.length + 1);\n }\n\n return packageId;\n}\n\nfunction readNonEmptyTrimmedString(\n value: string | undefined,\n): string | undefined {\n const trimmed = value?.trim();\n return trimmed ? trimmed : undefined;\n}\n\nfunction isWidgetPackageOwnerKind(\n value: string | undefined,\n): value is WidgetPackageOwnerKind {\n return value === \"company\" || value === \"droplet\";\n}\n\nfunction isUrlSafeDottedIdentifier(value: string): boolean {\n return URL_SAFE_DOTTED_IDENTIFIER_PATTERN.test(value);\n}\n\nfunction isUrlSafeWidgetName(value: string): boolean {\n return URL_SAFE_WIDGET_NAME_PATTERN.test(value);\n}\n\nfunction isUrlSafeSemver(value: string): boolean {\n return SEMVER_URL_SAFE_PATTERN.test(value);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import { execa } from \"execa\";\nimport fs from \"fs-extra\";\nimport path from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport { type Result, success, failure } from \"@fluid-app/fluid-cli\";\nimport {\n loadSourceWidgetPackages,\n resolvePortalWidgetSourceConfig,\n} from \"./widget-package-config.js\";\nimport {\n buildWidgetPackageDescriptor,\n getWidgetPackageDescriptorPackageId,\n validateSingleSourceWidgetPackage,\n type ValidatedWidgetPackageBuild,\n type WidgetPackageOwnerKind,\n} from \"./widget-package-validation.js\";\nimport {\n collectWidgetPackageArtifacts,\n createPublishManifestMetadata,\n isWidgetPackageCssArtifactPath,\n} from \"./widget-package-artifacts.js\";\n\nconst DEFAULT_PUBLISH_DIR = \".fluid/widget-dist\";\nconst DEFAULT_RUNTIME_VERSION = \"1\";\nconst TEMP_BUILD_DIR = \".fluid/widget-build\";\nconst TEMP_CLI_DIR = \".fluid/tmp\";\nconst PROJECT_VITE_CONFIG_CANDIDATES = [\n \"vite.config.ts\",\n \"vite.config.mts\",\n \"vite.config.js\",\n \"vite.config.mjs\",\n] as const;\nconst BLOCKED_FLUID_PROJECT_PLUGIN_NAMES = [\n \"fluid-manifest-plugin\",\n \"fluid-preview-plugin\",\n \"fluid-builder-preview\",\n \"fluid-builder-preview-standalone\",\n \"fluid-portal-dev\",\n \"fluid-backend-dev\",\n] as const;\nconst WIDGET_PACKAGE_QUEUE_GLOBAL = \"FluidWidgetPackageQueue\";\nconst require = createRequire(import.meta.url);\n\nexport interface BuildSharedWidgetPackageOptions {\n readonly projectDir: string;\n readonly publishDir?: string;\n readonly owner?: WidgetPackageOwnerKind;\n}\n\nexport interface SharedWidgetPackageBuildResult {\n readonly publishDir: string;\n readonly packageId: string;\n readonly version: string;\n readonly manifestPath: string;\n readonly publishManifestPath: string;\n readonly widgetScriptPath: string;\n}\n\nexport interface SharedWidgetPackageBuildError {\n readonly code:\n | \"CONFIG_LOAD_FAILED\"\n | \"VALIDATION_FAILED\"\n | \"INVALID_PUBLISH_DIR\"\n | \"WRITE_FAILED\";\n readonly message: string;\n readonly details?: string;\n}\n\nexport interface ValidateSharedWidgetPackagePublishDirOptions {\n readonly optionName?: string;\n}\n\nexport function validateSharedWidgetPackagePublishDir(\n projectDir: string,\n publishDir: string = DEFAULT_PUBLISH_DIR,\n options: ValidateSharedWidgetPackagePublishDirOptions = {},\n): void {\n const label = options.optionName ?? \"publishDir\";\n\n if (path.isAbsolute(publishDir)) {\n throw new Error(`${label} must be relative to the project directory.`);\n }\n\n const normalizedPublishDir = normalizePublishDirForValidation(publishDir);\n if (\n normalizedPublishDir === \".fluid\" ||\n !normalizedPublishDir.startsWith(\".fluid/\")\n ) {\n throw new Error(`${label} must be a relative path under .fluid/.`);\n }\n\n if (isPathWithinReservedDir(normalizedPublishDir, TEMP_BUILD_DIR)) {\n throw new Error(\n `${label} must not be ${TEMP_BUILD_DIR} because it is reserved for temporary builder output.`,\n );\n }\n\n if (isPathWithinReservedDir(normalizedPublishDir, TEMP_CLI_DIR)) {\n throw new Error(\n `${label} must not be ${TEMP_CLI_DIR} because it is reserved for Fluid CLI temporary files.`,\n );\n }\n\n const resolvedProjectDir = path.resolve(projectDir);\n const resolvedPublishDir = path.resolve(resolvedProjectDir, publishDir);\n const relative = path.relative(resolvedProjectDir, resolvedPublishDir);\n\n if (\n relative === \"\" ||\n relative.startsWith(\"..\") ||\n path.isAbsolute(relative)\n ) {\n throw new Error(`${label} must stay inside the project directory.`);\n }\n}\n\nexport async function buildSharedWidgetPackage(\n options: BuildSharedWidgetPackageOptions,\n): Promise<\n Result<SharedWidgetPackageBuildResult, SharedWidgetPackageBuildError>\n> {\n const publishDirInput = options.publishDir ?? DEFAULT_PUBLISH_DIR;\n try {\n await validateWidgetPackageOutputPaths(options.projectDir, publishDirInput);\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n return failure({\n code: \"INVALID_PUBLISH_DIR\",\n message: \"Unsafe widget package publish directory\",\n details: error.message,\n });\n }\n\n const sourcePackageResult = await loadSourceWidgetPackages(\n options.projectDir,\n );\n if (!sourcePackageResult.success) {\n return failure({\n code: \"CONFIG_LOAD_FAILED\",\n message: sourcePackageResult.error.message,\n details: sourcePackageResult.error.details,\n });\n }\n\n const validation = validateSingleSourceWidgetPackage(\n sourcePackageResult.value,\n { owner: options.owner },\n );\n if (!validation.success || !validation.value) {\n return failure({\n code: \"VALIDATION_FAILED\",\n message: validation.errors.map((error) => error.message).join(\"\\n\"),\n });\n }\n\n try {\n await validateWidgetPackageOutputPaths(options.projectDir, publishDirInput);\n\n const publishDir = path.resolve(options.projectDir, publishDirInput);\n await fs.emptyDir(publishDir);\n\n const tempDir = path.resolve(options.projectDir, TEMP_BUILD_DIR);\n await fs.emptyDir(tempDir);\n try {\n await buildWidgetScriptBundle({\n projectDir: options.projectDir,\n tempDir,\n publishDir,\n validated: validation.value,\n });\n } finally {\n await fs.remove(tempDir).catch(() => {});\n }\n\n const cssUrls = await collectCssUrls(publishDir);\n const descriptor = buildWidgetPackageDescriptor(validation.value, {\n cssUrls,\n });\n const manifestContent = stableStringify(descriptor);\n const publishPackageId = descriptor.packageId;\n\n const manifestPath = path.join(publishDir, \"manifest.json\");\n const widgetScriptPath = path.join(publishDir, \"widget.js\");\n const publishManifestPath = path.join(publishDir, \"publish-manifest.json\");\n\n await fs.writeFile(manifestPath, manifestContent, \"utf-8\");\n\n const artifacts = await collectWidgetPackageArtifacts(publishDir);\n const publishManifest = createPublishManifestMetadata({\n packageId: publishPackageId,\n version: validation.value.version,\n cliVersion: readCliVersion(),\n runtimeVersion: DEFAULT_RUNTIME_VERSION,\n manifestContent,\n artifacts,\n });\n await fs.writeFile(\n publishManifestPath,\n stableStringify(publishManifest),\n \"utf-8\",\n );\n\n return success({\n publishDir,\n packageId: getWidgetPackageDescriptorPackageId(validation.value),\n version: validation.value.version,\n manifestPath,\n publishManifestPath,\n widgetScriptPath,\n });\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n const isPublishDirValidationError =\n /^(publishDir|reserved temporary build directory) /.test(error.message);\n return failure({\n code: isPublishDirValidationError\n ? \"INVALID_PUBLISH_DIR\"\n : \"WRITE_FAILED\",\n message: isPublishDirValidationError\n ? \"Unsafe widget package publish directory\"\n : \"Failed to build shared widget package artifacts\",\n details: error.message,\n });\n }\n}\n\nexport function createWidgetPackageEntrySource(options: {\n readonly configImportPath: string;\n readonly validated: ValidatedWidgetPackageBuild;\n}): string {\n const runtimePackageId = getWidgetPackageDescriptorPackageId(\n options.validated,\n );\n\n return `import * as widgetConfig from ${JSON.stringify(options.configImportPath)};\nimport { createElement } from \"react\";\n\nconst SOURCE_PACKAGE_MARKER = \"__fluidSourceWidgetPackage\";\nconst WIDGET_PACKAGE_ID = ${JSON.stringify(runtimePackageId)};\nconst WIDGET_PACKAGE_VERSION = ${JSON.stringify(options.validated.version)};\nconst descriptors = ${JSON.stringify(options.validated.widgets, null, 2)};\n\nfunction isSourceWidgetPackage(value) {\n return Boolean(value && typeof value === \"object\" && value[SOURCE_PACKAGE_MARKER] === true);\n}\n\nfunction collectSourceWidgetPackages(mod) {\n return [\n mod.widgetPackage,\n ...(Array.isArray(mod.widgetPackages) ? mod.widgetPackages : []),\n mod.default,\n ].filter(isSourceWidgetPackage);\n}\n\nconst sourcePackage = collectSourceWidgetPackages(widgetConfig)[0];\nif (!sourcePackage) {\n throw new Error(\"No Fluid source widget package found while loading widget package bundle.\");\n}\n\nconst componentsByName = new Map(\n sourcePackage.widgets.map((widget) => [widget.name, widget.component]),\n);\n\nfunction createScopedWidgetComponent(component, descriptor) {\n const wrapperTagName = descriptor.container === \"inline\" ? \"span\" : \"div\";\n const WrappedFluidWidgetComponent = (props) => createElement(\n wrapperTagName,\n {\n \"data-fluid-widget-package\": WIDGET_PACKAGE_ID,\n \"data-fluid-widget-version\": WIDGET_PACKAGE_VERSION,\n \"data-fluid-widget-name\": descriptor.name,\n },\n // PortalContainerProvider is not imported here because standalone widget packages\n // only depend on @fluid-app/portal-sdk, which does not currently expose a\n // public portal-container provider. Radix/ui-primitives portals remain a\n // residual isolation risk until a public widget-safe provider is available.\n createElement(component, props),\n );\n WrappedFluidWidgetComponent.displayName = \"FluidWidgetPackage(\" + WIDGET_PACKAGE_ID + \"/\" + descriptor.name + \")\";\n return WrappedFluidWidgetComponent;\n}\n\nconst widgets = descriptors.map((descriptor) => {\n const component = componentsByName.get(descriptor.name);\n if (typeof component !== \"function\" && typeof component !== \"object\") {\n throw new Error(\"Widget package is missing component for \" + descriptor.name + \".\");\n }\n return { ...descriptor, component: createScopedWidgetComponent(component, descriptor) };\n});\n\nvar _fluidWidgets = globalObject.FluidWidgets;\nif (!_fluidWidgets || typeof _fluidWidgets.registerPackage !== \"function\") {\n throw new Error(\"FluidWidgets registry is not installed.\");\n}\n\n_fluidWidgets.registerPackage({\n packageId: ${JSON.stringify(runtimePackageId)},\n version: ${JSON.stringify(options.validated.version)},\n widgets,\n});\n`;\n}\n\nasync function buildWidgetScriptBundle(options: {\n readonly projectDir: string;\n readonly tempDir: string;\n readonly publishDir: string;\n readonly validated: ValidatedWidgetPackageBuild;\n}): Promise<void> {\n const sourceConfig = await resolvePortalWidgetSourceConfig(\n options.projectDir,\n );\n if (!sourceConfig) {\n throw new Error(\"No portal widget source config found.\");\n }\n\n const entryPath = path.join(options.tempDir, \"widget-entry.ts\");\n const viteConfigPath = path.join(options.tempDir, \"vite.config.mjs\");\n await fs.writeFile(\n entryPath,\n createWidgetPackageEntrySource({\n configImportPath: pathToFileURL(sourceConfig.path).href,\n validated: options.validated,\n }),\n \"utf-8\",\n );\n await fs.writeFile(\n viteConfigPath,\n createViteConfigSource({\n entryPath,\n packageId: getWidgetPackageDescriptorPackageId(options.validated),\n packageVersion: options.validated.version,\n publishDir: options.publishDir,\n projectConfigPath: await resolveProjectViteConfigPath(options.projectDir),\n }),\n \"utf-8\",\n );\n\n const viteCliPath = resolveViteCliPath(options.projectDir);\n await execa(\n process.execPath,\n [viteCliPath, \"build\", \"--config\", viteConfigPath],\n {\n cwd: options.projectDir,\n stdio: \"pipe\",\n env: { ...process.env, NODE_ENV: \"production\" },\n },\n );\n\n const widgetScriptPath = path.join(options.publishDir, \"widget.js\");\n const widgetScriptContent = await fs.readFile(widgetScriptPath, \"utf-8\");\n await fs.writeFile(\n widgetScriptPath,\n wrapWidgetPackageScript(widgetScriptContent),\n \"utf-8\",\n );\n}\n\nexport function wrapWidgetPackageScript(widgetScriptContent: string): string {\n return `;(function () {\n var globalObject = window;\n var runWidgetPackage = function fluidWidgetPackageFactory() {\n // Intentionally shadow Rollup's expected FluidShared global with the wrapper-scoped host globals.\n var FluidShared = globalObject.FluidShared;\n if (!FluidShared) {\n throw new Error(\"window.FluidShared is not installed.\");\n }\n${indentScript(widgetScriptContent, \" \")}\n };\n\n if (globalObject.FluidShared) {\n runWidgetPackage();\n return;\n }\n\n var queue = globalObject.${WIDGET_PACKAGE_QUEUE_GLOBAL};\n if (!Array.isArray(queue)) {\n queue = [];\n globalObject.${WIDGET_PACKAGE_QUEUE_GLOBAL} = queue;\n }\n queue.push(runWidgetPackage);\n})();\n`;\n}\n\nfunction indentScript(source: string, indent: string): string {\n return source\n .split(\"\\n\")\n .map((line) => (line.length > 0 ? `${indent}${line}` : line))\n .join(\"\\n\");\n}\n\nexport function resolveViteCliPath(projectDir: string): string {\n const projectRequire = createRequire(path.join(projectDir, \"package.json\"));\n const projectViteCliPath = resolveViteCliPathFromRequire(projectRequire);\n if (projectViteCliPath) return projectViteCliPath;\n\n const cliViteCliPath = resolveViteCliPathFromRequire(require);\n if (cliViteCliPath) return cliViteCliPath;\n\n throw new Error(\n \"Unable to resolve Vite for the portal project. Install the project dependencies and ensure vite is available before building widget packages.\",\n );\n}\n\nexport async function resolveProjectViteConfigPath(\n projectDir: string,\n): Promise<string | undefined> {\n for (const fileName of PROJECT_VITE_CONFIG_CANDIDATES) {\n const candidate = path.join(projectDir, fileName);\n if (await fs.pathExists(candidate)) return candidate;\n }\n\n return undefined;\n}\n\nexport function createViteConfigSource(options: {\n readonly entryPath: string;\n readonly packageId: string;\n readonly packageVersion: string;\n readonly publishDir: string;\n readonly projectConfigPath?: string;\n}): string {\n const widgetConfigSource = createWidgetViteConfigObjectSource({\n ...options,\n disableConfigFileLookup: !options.projectConfigPath,\n });\n\n if (!options.projectConfigPath) {\n return `import { defineConfig } from \"vite\";\n\nexport default defineConfig(${widgetConfigSource});\n`;\n }\n\n return `import { defineConfig, loadConfigFromFile, mergeConfig } from \"vite\";\n\nconst projectConfigPath = ${JSON.stringify(options.projectConfigPath)};\nconst widgetConfig = ${widgetConfigSource};\nconst blockedFluidPluginNames = new Set(${JSON.stringify(BLOCKED_FLUID_PROJECT_PLUGIN_NAMES)});\n\nfunction isAllowedProjectPlugin(plugin) {\n return !plugin || typeof plugin !== \"object\" || !blockedFluidPluginNames.has(plugin.name);\n}\n\nfunction sanitizeProjectPlugins(pluginOption) {\n if (!Array.isArray(pluginOption)) {\n return isAllowedProjectPlugin(pluginOption) ? pluginOption : [];\n }\n\n return pluginOption\n .map((plugin) => Array.isArray(plugin) ? sanitizeProjectPlugins(plugin) : plugin)\n .filter(isAllowedProjectPlugin);\n}\n\nfunction copyProjectConfigValue(source, target, key) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n target[key] = source[key];\n }\n}\n\nfunction sanitizeProjectConfig(config) {\n if (!config || typeof config !== \"object\") return {};\n\n const sanitized = {};\n if (Object.prototype.hasOwnProperty.call(config, \"plugins\")) {\n sanitized.plugins = sanitizeProjectPlugins(config.plugins);\n }\n copyProjectConfigValue(config, sanitized, \"resolve\");\n copyProjectConfigValue(config, sanitized, \"define\");\n copyProjectConfigValue(config, sanitized, \"css\");\n copyProjectConfigValue(config, sanitized, \"esbuild\");\n copyProjectConfigValue(config, sanitized, \"json\");\n copyProjectConfigValue(config, sanitized, \"assetsInclude\");\n copyProjectConfigValue(config, sanitized, \"envDir\");\n copyProjectConfigValue(config, sanitized, \"envPrefix\");\n return sanitized;\n}\n\nexport default defineConfig(async (configEnv) => {\n const projectConfig = await loadConfigFromFile(configEnv, projectConfigPath);\n const safeProjectConfig = sanitizeProjectConfig(projectConfig?.config ?? {});\n return mergeConfig(safeProjectConfig, widgetConfig);\n});\n`;\n}\n\nfunction createWidgetViteConfigObjectSource(options: {\n readonly entryPath: string;\n readonly packageId: string;\n readonly packageVersion: string;\n readonly publishDir: string;\n readonly disableConfigFileLookup: boolean;\n}): string {\n const configFileSource = options.disableConfigFileLookup\n ? \" configFile: false,\\n\"\n : \"\";\n\n return `(() => {\n const widgetPackageId = ${JSON.stringify(options.packageId)};\n const widgetPackageVersion = ${JSON.stringify(options.packageVersion)};\n const widgetPackageScopeSelector = '[data-fluid-widget-package=\"' + widgetPackageId + '\"][data-fluid-widget-version=\"' + widgetPackageVersion + '\"]';\n const widgetPackageGeneratedCssFileName = \"widget.css\";\n const widgetPackageKeyframePrefix = \"fluid-widget-\" + encodeCssIdentifier(widgetPackageId) + \"-\" + encodeCssIdentifier(widgetPackageVersion) + \"-\";\n const widgetPackageLayerPrefix = widgetPackageKeyframePrefix + \"layer-\";\n const widgetPackageHostDefaultLayerName = widgetPackageLayerPrefix + \"generated-host-defaults\";\n const widgetPackageHostDefaultRule = \"@layer \" + widgetPackageHostDefaultLayerName + \" { \" + widgetPackageScopeSelector + \" { display: contents; } }\";\n const widgetPackageContainerPrefix = widgetPackageKeyframePrefix + \"container-\";\n const widgetPackageCssGlobalNamePrefix = widgetPackageKeyframePrefix + \"css-name-\";\n const groupingAtRules = new Set([\"media\", \"supports\", \"container\", \"document\", \"starting-style\"]);\n const unsafeSelectorPattern = /(^|[\\\\s>+~,])(:root|html|body)(?=$|[\\\\s.#:[>+~,)])/i;\n const universalSelectorPattern = /(^|[\\\\s>+~,])\\\\*(?=$|[\\\\s.#:[>+~,)])/g;\n const pseudoElementOnlySelectorPattern = /^::[A-Za-z-]+(?:\\\\([^)]*\\\\))?$/;\n\n function createFluidWidgetBuildInvariants() {\n return {\n copyPublicDir: false,\n emptyOutDir: false,\n outDir: ${JSON.stringify(options.publishDir)},\n sourcemap: false,\n lib: {\n entry: ${JSON.stringify(options.entryPath)},\n formats: [\"iife\"],\n name: \"FluidWidgetPackage\",\n fileName: () => \"widget.js\",\n },\n rollupOptions: {\n external: [\"react\", \"react-dom\", \"react/jsx-runtime\"],\n output: {\n globals: {\n react: \"FluidShared.React\",\n \"react-dom\": \"FluidShared.ReactDOM\",\n \"react/jsx-runtime\": \"FluidShared.ReactJsxRuntime\",\n },\n },\n },\n };\n }\n\n function fluidWidgetBuildInvariantsPlugin() {\n return {\n name: \"fluid-widget-build-invariants\",\n enforce: \"post\",\n config() {\n return { build: createFluidWidgetBuildInvariants() };\n },\n configResolved(config) {\n Object.assign(config.build, createFluidWidgetBuildInvariants());\n },\n };\n }\n\n function fluidWidgetCssIsolationPlugin() {\n return {\n name: \"fluid-widget-css-isolation\",\n enforce: \"post\",\n generateBundle(_outputOptions, bundle) {\n let hasCssAsset = false;\n for (const asset of Object.values(bundle)) {\n if (!asset || asset.type !== \"asset\" || !asset.fileName.endsWith(\".css\")) continue;\n hasCssAsset = true;\n const source = typeof asset.source === \"string\" ? asset.source : new TextDecoder().decode(asset.source);\n asset.source = isolateWidgetCssAsset(source, asset.fileName);\n }\n if (!hasCssAsset) {\n this.emitFile({\n type: \"asset\",\n fileName: widgetPackageGeneratedCssFileName,\n source: widgetPackageHostDefaultRule + \"\\\\n\",\n });\n }\n },\n };\n }\n\n function isolateWidgetCssAsset(css, assetName) {\n const keyframeNames = collectKeyframeNames(css);\n const fontFamilyNames = collectFontFamilyNames(css);\n const customPropertyNames = collectRegisteredCustomPropertyNames(css);\n const placementSensitivePrefix = readPlacementSensitiveCssPrefix(css, assetName);\n const isolatedCss = isolateCssRange(css, assetName, keyframeNames, fontFamilyNames, customPropertyNames, placementSensitivePrefix.endIndex, css.length).css;\n return placementSensitivePrefix.css + widgetPackageHostDefaultRule + \"\\\\n\" + isolatedCss;\n }\n\n function collectKeyframeNames(css) {\n const names = new Map();\n visitCssAtRules(css, (atRuleName, atRule) => {\n if (!isKeyframesAtRule(atRuleName)) return false;\n const match = /^@(?:-[A-Za-z]+-)?keyframes\\\\s+([^\\\\s{]+)/i.exec(atRule.prelude);\n const name = match?.[1];\n if (name && !names.has(name)) names.set(name, widgetPackageKeyframePrefix + name);\n return atRule.blockStart !== -1;\n });\n return names;\n }\n\n function collectFontFamilyNames(css) {\n const names = new Map();\n visitCssAtRules(css, (atRuleName, atRule) => {\n if (atRuleName !== \"font-face\" || atRule.blockStart === -1 || atRule.blockEnd === -1) return false;\n let familyName = \"\";\n rewriteDeclarationBlock(css.slice(atRule.blockStart + 1, atRule.blockEnd), (propertyName, rawProperty, value) => {\n if (propertyName === \"font-family\" && !familyName) {\n familyName = normalizeFontFamilyName(value);\n }\n return { property: rawProperty, value };\n });\n if (familyName && !names.has(familyName)) names.set(familyName, widgetPackageKeyframePrefix + familyName);\n return true;\n });\n return names;\n }\n\n function collectRegisteredCustomPropertyNames(css) {\n const names = new Map();\n visitCssAtRules(css, (atRuleName, atRule) => {\n if (atRuleName !== \"property\") return false;\n const match = /^@property\\\\s+(--[A-Za-z0-9_-]+)/i.exec(atRule.prelude);\n const name = match?.[1];\n if (name && !names.has(name)) names.set(name, \"--\" + widgetPackageKeyframePrefix + name.slice(2));\n return atRule.blockStart !== -1;\n });\n return names;\n }\n\n function visitCssAtRules(css, visitAtRule) {\n let index = 0;\n while (index < css.length) {\n if (cssStartsWithComment(css, index)) {\n const commentEnd = css.indexOf(\"*/\", index + 2);\n index = commentEnd === -1 ? css.length : commentEnd + 2;\n continue;\n }\n const char = css[index];\n if (char === '\"' || char === \"'\") {\n index = findCssStringEnd(css, index);\n continue;\n }\n if (char !== \"@\") {\n index += 1;\n continue;\n }\n const atRule = readRulePrelude(css, index, css.length);\n const blockEnd = atRule.blockStart === -1 ? -1 : findMatchingBrace(css, atRule.blockStart, css.length);\n const shouldSkipBlock = visitAtRule(readAtRuleName(atRule.prelude), { ...atRule, blockEnd });\n index = shouldSkipBlock && blockEnd !== -1 ? blockEnd + 1 : index + 1;\n }\n }\n\n function isolateCssRange(css, assetName, keyframeNames, fontFamilyNames, customPropertyNames, startIndex, endIndex) {\n let output = \"\";\n let index = startIndex;\n while (index < endIndex) {\n if (css.startsWith(\"/*\", index)) {\n const commentEnd = css.indexOf(\"*/\", index + 2);\n const nextIndex = commentEnd === -1 ? endIndex : commentEnd + 2;\n output += css.slice(index, nextIndex);\n index = nextIndex;\n continue;\n }\n\n if (/\\\\s/.test(css[index] ?? \"\")) {\n output += css[index];\n index += 1;\n continue;\n }\n\n if (css[index] === \"@\") {\n const atRule = readRulePrelude(css, index, endIndex);\n const atRuleName = readAtRuleName(atRule.prelude);\n if (atRule.blockStart === -1) {\n if (atRuleName === \"import\") {\n throw new Error('Unsupported @import rule in CSS asset \"' + assetName + '\" cannot be isolated safely. Self-host external CSS or fonts via @font-face in widget CSS so the build can isolate them.');\n }\n if (atRuleName === \"charset\" || atRuleName === \"namespace\") {\n throw new Error('Unsupported @' + atRuleName + ' rule in CSS asset \"' + assetName + '\" cannot be isolated safely after generated host defaults. Move @' + atRuleName + ' before all non-@charset/@namespace rules.');\n }\n if (atRuleName === \"layer\") {\n output += rewriteLayerPrelude(atRule.prelude) + css.slice(index + atRule.prelude.length, atRule.end);\n index = atRule.end;\n continue;\n }\n output += css.slice(index, atRule.end);\n index = atRule.end;\n continue;\n }\n\n const blockEnd = findMatchingBrace(css, atRule.blockStart, endIndex);\n if (blockEnd === -1) {\n output += css.slice(index, endIndex);\n index = endIndex;\n continue;\n }\n\n const ruleHeader = css.slice(index, atRule.blockStart + 1);\n if (isKeyframesAtRule(atRuleName)) {\n output += rewriteKeyframesHeader(ruleHeader, keyframeNames) + namespaceKeyframesBlock(css.slice(atRule.blockStart + 1, blockEnd), keyframeNames, fontFamilyNames, customPropertyNames, assetName) + \"}\";\n } else if (atRuleName === \"font-face\") {\n output += ruleHeader + namespaceFontFaceBlock(css.slice(atRule.blockStart + 1, blockEnd), fontFamilyNames, customPropertyNames) + \"}\";\n } else if (atRuleName === \"property\") {\n output += rewritePropertyHeader(ruleHeader, customPropertyNames) + namespaceCustomPropertyReferences(css.slice(atRule.blockStart + 1, blockEnd), customPropertyNames) + \"}\";\n } else if (atRuleName === \"layer\") {\n output += rewriteLayerPrelude(atRule.prelude) + css.slice(index + atRule.prelude.length, atRule.blockStart + 1) + isolateCssRange(css, assetName, keyframeNames, fontFamilyNames, customPropertyNames, atRule.blockStart + 1, blockEnd).css + \"}\";\n } else if (groupingAtRules.has(atRuleName)) {\n const groupingRuleHeader = atRuleName === \"container\" ? rewriteContainerAtRuleHeader(ruleHeader) : ruleHeader;\n output += groupingRuleHeader + isolateCssRange(css, assetName, keyframeNames, fontFamilyNames, customPropertyNames, atRule.blockStart + 1, blockEnd).css + \"}\";\n } else {\n throw new Error('Unsupported @' + atRuleName + ' rule in CSS asset \"' + assetName + '\" cannot be isolated safely.');\n }\n index = blockEnd + 1;\n continue;\n }\n\n const styleRule = readRulePrelude(css, index, endIndex);\n if (styleRule.blockStart === -1) {\n output += css.slice(index, styleRule.end);\n index = styleRule.end;\n continue;\n }\n\n const styleBlockEnd = findMatchingBrace(css, styleRule.blockStart, endIndex);\n if (styleBlockEnd === -1) {\n output += css.slice(index, endIndex);\n index = endIndex;\n continue;\n }\n\n output += isolateSelectorList(styleRule.prelude, assetName) + \"{\" + namespaceStyleBlock(css.slice(styleRule.blockStart + 1, styleBlockEnd), keyframeNames, fontFamilyNames, customPropertyNames, assetName) + \"}\";\n index = styleBlockEnd + 1;\n }\n\n return { css: output, index };\n }\n\n function readPlacementSensitiveCssPrefix(css, assetName) {\n let output = \"\";\n let index = 0;\n let hasNamespace = false;\n while (index < css.length) {\n const leadingStart = index;\n index = skipCssWhitespaceAndComments(css, index);\n const leading = css.slice(leadingStart, index);\n if (css[index] !== \"@\") {\n return { css: output + leading, endIndex: index };\n }\n\n const atRule = readRulePrelude(css, index, css.length);\n const atRuleName = readAtRuleName(atRule.prelude);\n if (atRuleName !== \"charset\" && atRuleName !== \"namespace\") {\n return { css: output + leading, endIndex: index };\n }\n if (atRule.blockStart !== -1) {\n throw new Error('Unsupported @' + atRuleName + ' rule in CSS asset \"' + assetName + '\" cannot be isolated safely.');\n }\n if (atRuleName === \"charset\" && hasNamespace) {\n throw new Error('Unsupported @charset rule in CSS asset \"' + assetName + '\" cannot be isolated safely after @namespace. Move @charset before @namespace.');\n }\n if (atRuleName === \"namespace\") hasNamespace = true;\n output += leading + css.slice(index, atRule.end);\n index = atRule.end;\n }\n return { css: output, endIndex: index };\n }\n\n function readRulePrelude(css, startIndex, endIndex) {\n let index = startIndex;\n let quote = \"\";\n let bracketDepth = 0;\n let parenDepth = 0;\n while (index < endIndex) {\n const char = css[index];\n if (quote) {\n if (char === \"\\\\\\\\\") index += 2;\n else {\n if (char === quote) quote = \"\";\n index += 1;\n }\n continue;\n }\n if (cssStartsWithComment(css, index)) {\n const commentEnd = css.indexOf(\"*/\", index + 2);\n index = commentEnd === -1 ? endIndex : Math.min(commentEnd + 2, endIndex);\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n index += 1;\n continue;\n }\n if (char === \"[\") bracketDepth += 1;\n else if (char === \"]\") bracketDepth = Math.max(0, bracketDepth - 1);\n else if (char === \"(\") parenDepth += 1;\n else if (char === \")\") parenDepth = Math.max(0, parenDepth - 1);\n else if (bracketDepth === 0 && parenDepth === 0 && char === \"{\") {\n return { prelude: css.slice(startIndex, index), blockStart: index, end: index + 1 };\n } else if (bracketDepth === 0 && parenDepth === 0 && char === \";\") {\n return { prelude: css.slice(startIndex, index), blockStart: -1, end: index + 1 };\n }\n index += 1;\n }\n return { prelude: css.slice(startIndex, endIndex), blockStart: -1, end: endIndex };\n }\n\n function findMatchingBrace(css, openBraceIndex, endIndex) {\n let depth = 1;\n let index = openBraceIndex + 1;\n let quote = \"\";\n while (index < endIndex) {\n const char = css[index];\n if (quote) {\n if (char === \"\\\\\\\\\") index += 2;\n else {\n if (char === quote) quote = \"\";\n index += 1;\n }\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n index += 1;\n continue;\n }\n if (css.startsWith(\"/*\", index)) {\n const commentEnd = css.indexOf(\"*/\", index + 2);\n index = commentEnd === -1 ? endIndex : commentEnd + 2;\n continue;\n }\n if (char === \"{\") depth += 1;\n else if (char === \"}\") {\n depth -= 1;\n if (depth === 0) return index;\n }\n index += 1;\n }\n return -1;\n }\n\n function readAtRuleName(prelude) {\n const match = /^@([A-Za-z-]+)/.exec(prelude.trim());\n return match?.[1]?.toLowerCase() ?? \"\";\n }\n\n function isKeyframesAtRule(atRuleName) {\n return atRuleName === \"keyframes\" || atRuleName.endsWith(\"-keyframes\");\n }\n\n function rewriteKeyframesHeader(header, keyframeNames) {\n return header.replace(/(@(?:-[A-Za-z]+-)?keyframes\\\\s+)([^\\\\s{]+)/, (_match, prefix, name) => prefix + (keyframeNames.get(name) ?? name));\n }\n\n function splitSelectorList(selectorList) {\n const selectors = [];\n let current = \"\";\n let quote = \"\";\n let bracketDepth = 0;\n let parenDepth = 0;\n for (let index = 0; index < selectorList.length; index += 1) {\n const char = selectorList[index];\n if (quote) {\n current += char;\n if (char === \"\\\\\\\\\") {\n index += 1;\n current += selectorList[index] ?? \"\";\n } else if (char === quote) quote = \"\";\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n current += char;\n continue;\n }\n if (cssStartsWithComment(selectorList, index)) {\n const commentEnd = selectorList.indexOf(\"*/\", index + 2);\n const nextIndex = commentEnd === -1 ? selectorList.length : commentEnd + 2;\n current += selectorList.slice(index, nextIndex);\n index = nextIndex - 1;\n continue;\n }\n if (char === \"[\") bracketDepth += 1;\n else if (char === \"]\") bracketDepth = Math.max(0, bracketDepth - 1);\n else if (char === \"(\") parenDepth += 1;\n else if (char === \")\") parenDepth = Math.max(0, parenDepth - 1);\n if (char === \",\" && bracketDepth === 0 && parenDepth === 0) {\n selectors.push(current);\n current = \"\";\n } else current += char;\n }\n selectors.push(current);\n return selectors;\n }\n\n function isolateSelectorList(selectorList, assetName) {\n return splitSelectorList(selectorList).map((selector) => isolateSelector(selector, assetName)).join(\",\");\n }\n\n function isolateSelector(selector, assetName) {\n const leadingWhitespace = selector.match(/^\\\\s*/)?.[0] ?? \"\";\n const trailingWhitespace = selector.match(/\\\\s*$/)?.[0] ?? \"\";\n const trimmed = selector.trim();\n assertSafeSelector(trimmed, assetName);\n if (trimmed.includes(\":host\")) {\n return leadingWhitespace + isolateHostSelector(trimmed, assetName) + trailingWhitespace;\n }\n return leadingWhitespace + widgetPackageScopeSelector + \" \" + trimmed + trailingWhitespace;\n }\n\n function isolateHostSelector(selector, assetName) {\n if (!selector.startsWith(\":host\")) {\n throw new Error('Unsupported :host selector \"' + selector + '\" in CSS asset \"' + assetName + '\" cannot be isolated safely.');\n }\n const match = /^:host(?:\\\\(([^()]*)\\\\))?($|[\\\\s>+~].*)/.exec(selector);\n if (!match) {\n throw new Error('Unsupported :host selector \"' + selector + '\" in CSS asset \"' + assetName + '\" cannot be isolated safely.');\n }\n const hostSelector = (match[1] ?? \"\").trim();\n const selectorAfterHost = match[2] ?? \"\";\n const firstSelectorAfterHostIndex = skipCssWhitespaceAndComments(selectorAfterHost, 0);\n const firstSelectorAfterHostChar = selectorAfterHost[firstSelectorAfterHostIndex] ?? \"\";\n if (hostSelector.includes(\",\") || hasTopLevelHostArgumentCombinator(hostSelector) || firstSelectorAfterHostChar === \"+\" || firstSelectorAfterHostChar === \"~\" || (hostSelector && (unsafeSelectorPattern.test(hostSelector) || hasUnsafeUniversalSelector(hostSelector)))) {\n throw new Error('Unsupported :host selector \"' + selector + '\" in CSS asset \"' + assetName + '\" cannot be isolated safely.');\n }\n return widgetPackageScopeSelector + hostSelector + selectorAfterHost;\n }\n\n function hasTopLevelHostArgumentCombinator(value) {\n let quote = \"\";\n let bracketDepth = 0;\n let hasSelectorBeforeWhitespace = false;\n let index = 0;\n while (index < value.length) {\n const char = value[index];\n if (quote) {\n if (char === \"\\\\\\\\\") index += 2;\n else {\n if (char === quote) quote = \"\";\n index += 1;\n }\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n index += 1;\n continue;\n }\n if (char === \"[\") {\n bracketDepth += 1;\n hasSelectorBeforeWhitespace = true;\n } else if (char === \"]\") {\n bracketDepth = Math.max(0, bracketDepth - 1);\n } else if (bracketDepth === 0 && (char === \"+\" || char === \"~\" || char === \">\")) {\n return true;\n } else if (bracketDepth === 0 && /\\\\s/.test(char)) {\n const nextIndex = skipCssWhitespaceAndComments(value, index);\n if (hasSelectorBeforeWhitespace && nextIndex < value.length) return true;\n index = nextIndex;\n continue;\n } else if (bracketDepth === 0 && cssStartsWithComment(value, index)) {\n const nextIndex = skipCssWhitespaceAndComments(value, index);\n if (hasSelectorBeforeWhitespace && nextIndex < value.length) return true;\n index = nextIndex;\n continue;\n } else if (bracketDepth === 0 && !/\\\\s/.test(char)) {\n hasSelectorBeforeWhitespace = true;\n }\n index += 1;\n }\n return false;\n }\n\n function assertSafeSelector(selector, assetName) {\n if (!selector || unsafeSelectorPattern.test(selector) || hasUnsafeUniversalSelector(selector) || pseudoElementOnlySelectorPattern.test(selector)) {\n throw new Error('Unsafe selector \"' + selector + '\" in CSS asset \"' + assetName + '\" cannot be isolated safely.');\n }\n }\n\n function hasUnsafeUniversalSelector(selector) {\n universalSelectorPattern.lastIndex = 0;\n let match;\n while ((match = universalSelectorPattern.exec(selector)) !== null) {\n const universalStart = match.index + match[1].length;\n if (!hasAnchoringSelectorBefore(selector.slice(0, universalStart))) return true;\n }\n return false;\n }\n\n function hasAnchoringSelectorBefore(value) {\n return stripCssComments(value).replace(/[\\\\s>+~]+/g, \"\").length > 0;\n }\n\n function namespaceKeyframesBlock(block, keyframeNames, fontFamilyNames, customPropertyNames, assetName) {\n let output = \"\";\n let index = 0;\n while (index < block.length) {\n if (cssStartsWithComment(block, index)) {\n const commentEnd = block.indexOf(\"*/\", index + 2);\n const nextIndex = commentEnd === -1 ? block.length : commentEnd + 2;\n output += block.slice(index, nextIndex);\n index = nextIndex;\n continue;\n }\n if (/\\\\s/.test(block[index] ?? \"\")) {\n output += block[index];\n index += 1;\n continue;\n }\n const keyframeRule = readRulePrelude(block, index, block.length);\n if (keyframeRule.blockStart === -1) {\n output += block.slice(index, keyframeRule.end);\n index = keyframeRule.end;\n continue;\n }\n const keyframeBlockEnd = findMatchingBrace(block, keyframeRule.blockStart, block.length);\n if (keyframeBlockEnd === -1) {\n output += block.slice(index);\n index = block.length;\n continue;\n }\n output += keyframeRule.prelude + \"{\" + namespaceStyleBlock(block.slice(keyframeRule.blockStart + 1, keyframeBlockEnd), keyframeNames, fontFamilyNames, customPropertyNames, assetName) + \"}\";\n index = keyframeBlockEnd + 1;\n }\n return output;\n }\n\n function namespaceStyleBlock(block, keyframeNames, fontFamilyNames, customPropertyNames, assetName) {\n assertNoNestedCssBlock(block, assetName);\n return rewriteDeclarationBlock(block, (propertyName, rawProperty, value) => {\n const nextProperty = namespaceCustomPropertyName(rawProperty, propertyName, customPropertyNames);\n let nextValue = value;\n if (propertyName === \"animation\" || propertyName === \"-webkit-animation\") {\n nextValue = namespaceAnimationShorthandValue(nextValue, keyframeNames);\n } else if (propertyName === \"animation-name\" || propertyName === \"-webkit-animation-name\") {\n nextValue = namespaceAnimationNameValue(nextValue, keyframeNames);\n } else if (propertyName === \"font-family\") {\n nextValue = namespaceFontFamilyValue(nextValue, fontFamilyNames);\n } else if (propertyName === \"font\") {\n nextValue = namespaceFontShorthandValue(nextValue, fontFamilyNames, assetName);\n }\n if (propertyName === \"container-name\") {\n nextValue = namespaceContainerNameValue(nextValue);\n } else if (propertyName === \"container\") {\n nextValue = namespaceContainerShorthandValue(nextValue);\n }\n if (propertyName === \"transition\" || propertyName === \"transition-property\" || propertyName === \"will-change\") {\n nextValue = namespaceCustomPropertyIdentifierValue(nextValue, customPropertyNames);\n }\n if (propertyName === \"view-transition-name\" || propertyName === \"scroll-timeline-name\" || propertyName === \"animation-timeline\") {\n nextValue = namespaceCssGlobalNameValue(nextValue);\n }\n nextValue = namespaceCustomPropertyReferencesValue(nextValue, customPropertyNames);\n return { property: nextProperty, value: nextValue };\n });\n }\n\n function namespaceFontFaceBlock(block, fontFamilyNames, customPropertyNames) {\n return rewriteDeclarationBlock(block, (propertyName, rawProperty, value) => {\n const nextValue = propertyName === \"font-family\"\n ? namespaceFontFamilyValue(value, fontFamilyNames)\n : namespaceCustomPropertyReferencesValue(value, customPropertyNames);\n return { property: rawProperty, value: nextValue };\n });\n }\n\n function namespaceAnimationNameValue(value, keyframeNames) {\n return replaceCssValueOutsideProtectedRanges(value, (chunk) => {\n let nextChunk = chunk;\n for (const [name, scopedName] of keyframeNames) {\n nextChunk = nextChunk.replace(new RegExp(\"(^|[^A-Za-z0-9_-])\" + escapeRegExp(name) + \"(?=$|[^A-Za-z0-9_-])\", \"g\"), (_match, prefix) => prefix + scopedName);\n }\n return nextChunk;\n });\n }\n\n function namespaceAnimationShorthandValue(value, keyframeNames) {\n if (keyframeNames.size === 0) return value;\n return splitCssCommaList(value).map((item) => rewriteAnimationShorthandItem(item, keyframeNames)).join(\",\");\n }\n\n function rewriteAnimationShorthandItem(item, keyframeNames) {\n const tokens = readCssValueTokens(item);\n const reservedState = createAnimationShorthandReservedState();\n let output = \"\";\n let lastIndex = 0;\n for (const token of tokens) {\n const scopedName = keyframeNames.get(token.text);\n const isReservedToken = consumeAnimationShorthandReservedToken(token.text, reservedState);\n if (!scopedName || isReservedToken) continue;\n output += item.slice(lastIndex, token.start) + scopedName;\n lastIndex = token.end;\n }\n return output + item.slice(lastIndex);\n }\n\n function createAnimationShorthandReservedState() {\n return {\n duration: false,\n delay: false,\n timingFunction: false,\n iterationCount: false,\n direction: false,\n fillMode: false,\n playState: false,\n };\n }\n\n function consumeAnimationShorthandReservedToken(token, state) {\n const lower = token.toLowerCase();\n if (isAnimationTimeToken(token)) {\n if (!state.duration) {\n state.duration = true;\n return true;\n }\n if (!state.delay) {\n state.delay = true;\n return true;\n }\n return false;\n }\n if (!state.timingFunction && isAnimationTimingFunctionToken(lower)) {\n state.timingFunction = true;\n return true;\n }\n if (!state.iterationCount && isAnimationIterationCountToken(token, lower)) {\n state.iterationCount = true;\n return true;\n }\n if (!state.direction && animationDirectionKeywords.has(lower)) {\n state.direction = true;\n return true;\n }\n if (!state.fillMode && animationFillModeKeywords.has(lower)) {\n state.fillMode = true;\n return true;\n }\n if (!state.playState && animationPlayStateKeywords.has(lower)) {\n state.playState = true;\n return true;\n }\n if (animationGlobalKeywords.has(lower)) return true;\n return false;\n }\n\n function isAnimationTimeToken(token) {\n return /^-?(?:\\\\d+|\\\\d*\\\\.\\\\d+)(?:ms|s)$/i.test(token);\n }\n\n function isAnimationTimingFunctionToken(lowerToken) {\n return animationTimingFunctionKeywords.has(lowerToken) || lowerToken.includes(\"(\");\n }\n\n function isAnimationIterationCountToken(token, lowerToken) {\n return lowerToken === \"infinite\" || /^-?(?:\\\\d+|\\\\d*\\\\.\\\\d+)$/.test(token);\n }\n\n const animationTimingFunctionKeywords = new Set([\n \"ease\",\n \"ease-in\",\n \"ease-in-out\",\n \"ease-out\",\n \"linear\",\n \"step-end\",\n \"step-start\",\n ]);\n const animationDirectionKeywords = new Set([\"normal\", \"reverse\", \"alternate\", \"alternate-reverse\"]);\n const animationFillModeKeywords = new Set([\"none\", \"forwards\", \"backwards\", \"both\"]);\n const animationPlayStateKeywords = new Set([\"running\", \"paused\"]);\n const animationGlobalKeywords = new Set([\"inherit\", \"initial\", \"revert\", \"revert-layer\", \"unset\"]);\n\n function namespaceFontFamilyValue(value, fontFamilyNames) {\n if (fontFamilyNames.size === 0) return value;\n const important = splitCssImportantSuffix(value);\n return splitCssCommaList(important.value).map((family) => namespaceSingleFontFamily(family, fontFamilyNames)).join(\",\") + important.suffix;\n }\n\n function namespaceFontShorthandValue(value, fontFamilyNames, assetName) {\n if (fontFamilyNames.size === 0) return value;\n const familyStart = findFontShorthandFamilyStart(value);\n if (familyStart === -1) {\n if (fontShorthandReferencesScopedFontFamily(value, fontFamilyNames)) {\n throw new Error('Unsupported font shorthand in CSS asset \"' + assetName + '\" cannot be isolated safely. Use font-family with font-style/font-weight/font-size longhands, or use a supported font shorthand with an explicit font-size before the family list.');\n }\n return value;\n }\n return value.slice(0, familyStart) + namespaceFontFamilyValue(value.slice(familyStart), fontFamilyNames);\n }\n\n function fontShorthandReferencesScopedFontFamily(value, fontFamilyNames) {\n const tokens = readCssValueTokens(value);\n return tokens.some((token) => fontFamilyNames.has(normalizeFontFamilyName(token.text)));\n }\n\n function splitCssImportantSuffix(value) {\n const match = /!\\\\s*important\\\\s*$/i.exec(value);\n if (!match) return { value, suffix: \"\" };\n return {\n value: value.slice(0, match.index),\n suffix: value.slice(match.index),\n };\n }\n\n function namespaceSingleFontFamily(family, fontFamilyNames) {\n const leadingWhitespace = family.match(/^\\\\s*/)?.[0] ?? \"\";\n const trailingWhitespace = family.match(/\\\\s*$/)?.[0] ?? \"\";\n const trimmed = family.trim();\n const normalized = normalizeFontFamilyName(trimmed);\n const scopedName = fontFamilyNames.get(normalized);\n if (!scopedName) return family;\n const quote = trimmed[0] === '\"' || trimmed[0] === \"'\" ? trimmed[0] : \"\";\n return leadingWhitespace + (quote ? quote + scopedName + quote : scopedName) + trailingWhitespace;\n }\n\n function normalizeFontFamilyName(value) {\n const trimmed = value.trim();\n if ((trimmed.startsWith('\"') && trimmed.endsWith('\"')) || (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))) {\n return trimmed.slice(1, -1);\n }\n return trimmed;\n }\n\n function rewritePropertyHeader(header, customPropertyNames) {\n let nextHeader = header;\n for (const [name, scopedName] of customPropertyNames) {\n nextHeader = nextHeader.replace(new RegExp(\"(@property\\\\\\\\s+)\" + escapeRegExp(name) + \"(?=$|[\\\\\\\\s{])\", \"g\"), (_match, prefix) => prefix + scopedName);\n }\n return nextHeader;\n }\n\n function rewriteLayerPrelude(prelude) {\n const match = /^(@layer\\\\b)([\\\\s\\\\S]*)$/i.exec(prelude);\n if (!match) return prelude;\n const layerList = match[2] ?? \"\";\n if (!layerList.trim()) return prelude;\n return match[1] + splitCssCommaList(layerList).map(namespaceLayerName).join(\",\");\n }\n\n function namespaceLayerName(layerName) {\n const leadingWhitespace = layerName.match(/^\\\\s*/)?.[0] ?? \"\";\n const trailingWhitespace = layerName.match(/\\\\s*$/)?.[0] ?? \"\";\n const trimmed = layerName.trim();\n return trimmed ? leadingWhitespace + widgetPackageLayerPrefix + trimmed + trailingWhitespace : layerName;\n }\n\n function rewriteContainerAtRuleHeader(header) {\n if (!header.endsWith(\"{\")) return header;\n return rewriteContainerAtRulePrelude(header.slice(0, -1)) + \"{\";\n }\n\n function rewriteContainerAtRulePrelude(prelude) {\n const match = /^(@container\\\\b)([\\\\s\\\\S]*)$/i.exec(prelude);\n if (!match) return prelude;\n const condition = match[2] ?? \"\";\n const leadingWhitespace = condition.match(/^\\\\s*/)?.[0] ?? \"\";\n const conditionBody = condition.slice(leadingWhitespace.length);\n if (!conditionBody || conditionBody.startsWith(\"(\") || /^(?:style|scroll-state)\\\\s*\\\\(/.test(conditionBody)) {\n return prelude;\n }\n\n const tokens = readCssValueTokens(conditionBody);\n const nameToken = tokens[0];\n if (!nameToken || nameToken.start !== 0 || isContainerQueryConditionKeyword(nameToken.text) || isReservedContainerName(nameToken.text) || nameToken.text.includes(\"(\")) {\n return prelude;\n }\n return match[1] + leadingWhitespace + namespaceContainerName(nameToken.text) + conditionBody.slice(nameToken.end);\n }\n\n function namespaceContainerNameValue(value) {\n return replaceCssValueOutsideProtectedRanges(value, (chunk) => namespaceContainerNamesInChunk(chunk));\n }\n\n function namespaceContainerShorthandValue(value) {\n const slashIndex = findTopLevelSlash(value);\n if (slashIndex !== -1) {\n return namespaceContainerNameValue(value.slice(0, slashIndex)) + value.slice(slashIndex);\n }\n\n const trimmed = stripCssComments(value).trim().toLowerCase();\n if (isReservedContainerName(trimmed) || containerTypeKeywords.has(trimmed)) return value;\n return namespaceContainerNameValue(value);\n }\n\n function namespaceContainerNamesInChunk(chunk) {\n return chunk.replace(/(^|[^A-Za-z0-9_-])([A-Za-z_][A-Za-z0-9_-]*|-[A-Za-z_][A-Za-z0-9_-]*)(?=$|[^A-Za-z0-9_-])/g, (_match, prefix, name) => {\n if (isReservedContainerName(name)) return prefix + name;\n return prefix + namespaceContainerName(name);\n });\n }\n\n function namespaceContainerName(name) {\n return widgetPackageContainerPrefix + name;\n }\n\n function isReservedContainerName(name) {\n return containerNameReservedKeywords.has(name.toLowerCase());\n }\n\n function isContainerQueryConditionKeyword(name) {\n return containerQueryConditionKeywords.has(name.toLowerCase());\n }\n\n const containerTypeKeywords = new Set([\"normal\", \"size\", \"inline-size\", \"scroll-state\"]);\n const containerQueryConditionKeywords = new Set([\"not\", \"and\", \"or\"]);\n const containerNameReservedKeywords = new Set([\"none\", \"inherit\", \"initial\", \"revert\", \"revert-layer\", \"unset\"]);\n\n function namespaceCustomPropertyName(rawProperty, propertyName, customPropertyNames) {\n const scopedName = customPropertyNames.get(propertyName);\n if (!scopedName) return rawProperty;\n return rawProperty.replace(new RegExp(escapeRegExp(propertyName) + \"(?=\\\\\\\\s*$)\"), scopedName);\n }\n\n function namespaceCustomPropertyReferences(block, customPropertyNames) {\n return rewriteDeclarationBlock(block, (propertyName, rawProperty, value) => ({\n property: rawProperty,\n value: namespaceCustomPropertyReferencesValue(value, customPropertyNames),\n }));\n }\n\n function namespaceCustomPropertyReferencesValue(value, customPropertyNames) {\n if (customPropertyNames.size === 0) return value;\n return replaceCssValueOutsideProtectedRanges(value, (chunk) => {\n let nextChunk = chunk;\n for (const [name, scopedName] of customPropertyNames) {\n nextChunk = nextChunk.replace(new RegExp(\"(\\\\\\\\bvar\\\\\\\\(\\\\\\\\s*)\" + escapeRegExp(name) + \"(?=\\\\\\\\s*[,)])\", \"g\"), (_match, prefix) => prefix + scopedName);\n }\n return nextChunk;\n });\n }\n\n function namespaceCustomPropertyIdentifierValue(value, customPropertyNames) {\n if (customPropertyNames.size === 0) return value;\n return replaceCssValueOutsideProtectedRanges(value, (chunk) => {\n let nextChunk = chunk;\n for (const [name, scopedName] of customPropertyNames) {\n nextChunk = nextChunk.replace(new RegExp(\"(^|[^A-Za-z0-9_-])\" + escapeRegExp(name) + \"(?=$|[^A-Za-z0-9_-])\", \"g\"), (_match, prefix) => prefix + scopedName);\n }\n return nextChunk;\n });\n }\n\n function namespaceCssGlobalNameValue(value) {\n return replaceCssValueOutsideProtectedRanges(value, (chunk) => {\n return chunk.replace(/(^|[^A-Za-z0-9_-])(--[A-Za-z0-9_-]+|[A-Za-z_][A-Za-z0-9_-]*|-[A-Za-z_][A-Za-z0-9_-]*)(?=$|[^A-Za-z0-9_-])/g, (_match, prefix, name, offset, source) => {\n const nextChar = source[offset + prefix.length + name.length] ?? \"\";\n const beforeName = source.slice(0, offset + prefix.length);\n if (nextChar === \"(\" || /(?:^|[^A-Za-z0-9_-])var\\\\s*\\\\($/i.test(beforeName) || cssGlobalNameReservedKeywords.has(name.toLowerCase())) return prefix + name;\n return prefix + widgetPackageCssGlobalNamePrefix + name;\n });\n });\n }\n\n const cssGlobalNameReservedKeywords = new Set([\"auto\", \"none\", \"inherit\", \"initial\", \"revert\", \"revert-layer\", \"unset\"]);\n\n function assertNoNestedCssBlock(block, assetName) {\n let index = 0;\n let quote = \"\";\n let parenDepth = 0;\n while (index < block.length) {\n const char = block[index];\n if (quote) {\n if (char === \"\\\\\\\\\") index += 2;\n else {\n if (char === quote) quote = \"\";\n index += 1;\n }\n continue;\n }\n if (cssStartsWithComment(block, index)) {\n const commentEnd = block.indexOf(\"*/\", index + 2);\n index = commentEnd === -1 ? block.length : commentEnd + 2;\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n index += 1;\n continue;\n }\n if (char === \"(\") parenDepth += 1;\n else if (char === \")\") parenDepth = Math.max(0, parenDepth - 1);\n else if (char === \"{\" && parenDepth === 0) {\n throw new Error('Unsupported nested CSS rule in CSS asset \"' + assetName + '\" cannot be isolated safely. Compile nested CSS before building the widget package.');\n }\n index += 1;\n }\n }\n\n function rewriteDeclarationBlock(block, rewriteDeclaration) {\n let output = \"\";\n let declarationStart = 0;\n let index = 0;\n let quote = \"\";\n let parenDepth = 0;\n while (index < block.length) {\n const char = block[index];\n if (quote) {\n if (char === \"\\\\\\\\\") index += 2;\n else {\n if (char === quote) quote = \"\";\n index += 1;\n }\n continue;\n }\n if (cssStartsWithComment(block, index)) {\n const commentEnd = block.indexOf(\"*/\", index + 2);\n index = commentEnd === -1 ? block.length : commentEnd + 2;\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n index += 1;\n continue;\n }\n if (char === \"(\") parenDepth += 1;\n else if (char === \")\") parenDepth = Math.max(0, parenDepth - 1);\n else if (char === \";\" && parenDepth === 0) {\n output += rewriteDeclarationSegment(block.slice(declarationStart, index), rewriteDeclaration) + \";\";\n declarationStart = index + 1;\n }\n index += 1;\n }\n return output + rewriteDeclarationSegment(block.slice(declarationStart), rewriteDeclaration);\n }\n\n function rewriteDeclarationSegment(segment, rewriteDeclaration) {\n const colonIndex = findDeclarationColon(segment);\n if (colonIndex === -1) return segment;\n const rawProperty = segment.slice(0, colonIndex);\n const rawPropertyName = stripCssComments(rawProperty).trim();\n const propertyName = rawPropertyName.startsWith(\"--\") ? rawPropertyName : rawPropertyName.toLowerCase();\n if (!propertyName) return segment;\n const rewritten = rewriteDeclaration(propertyName, rawProperty, segment.slice(colonIndex + 1));\n return rewritten.property + \":\" + rewritten.value;\n }\n\n function findDeclarationColon(segment) {\n let index = 0;\n let quote = \"\";\n let parenDepth = 0;\n while (index < segment.length) {\n const char = segment[index];\n if (quote) {\n if (char === \"\\\\\\\\\") index += 2;\n else {\n if (char === quote) quote = \"\";\n index += 1;\n }\n continue;\n }\n if (cssStartsWithComment(segment, index)) {\n const commentEnd = segment.indexOf(\"*/\", index + 2);\n index = commentEnd === -1 ? segment.length : commentEnd + 2;\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n index += 1;\n continue;\n }\n if (char === \"(\") parenDepth += 1;\n else if (char === \")\") parenDepth = Math.max(0, parenDepth - 1);\n else if (char === \":\" && parenDepth === 0) return index;\n index += 1;\n }\n return -1;\n }\n\n function replaceCssValueOutsideProtectedRanges(value, replaceChunk) {\n let output = \"\";\n let chunkStart = 0;\n let index = 0;\n while (index < value.length) {\n if (cssStartsWithComment(value, index)) {\n output += replaceChunk(value.slice(chunkStart, index));\n const commentEnd = value.indexOf(\"*/\", index + 2);\n const nextIndex = commentEnd === -1 ? value.length : commentEnd + 2;\n output += value.slice(index, nextIndex);\n index = nextIndex;\n chunkStart = index;\n continue;\n }\n const char = value[index];\n if (char === '\"' || char === \"'\") {\n output += replaceChunk(value.slice(chunkStart, index));\n const stringEnd = findCssStringEnd(value, index);\n output += value.slice(index, stringEnd);\n index = stringEnd;\n chunkStart = index;\n continue;\n }\n if (isCssUrlFunctionStart(value, index)) {\n output += replaceChunk(value.slice(chunkStart, index));\n const urlEnd = findCssFunctionEnd(value, value.indexOf(\"(\", index));\n output += value.slice(index, urlEnd);\n index = urlEnd;\n chunkStart = index;\n continue;\n }\n index += 1;\n }\n return output + replaceChunk(value.slice(chunkStart));\n }\n\n function findCssStringEnd(value, quoteIndex) {\n const quote = value[quoteIndex];\n let index = quoteIndex + 1;\n while (index < value.length) {\n const char = value[index];\n if (char === \"\\\\\\\\\") index += 2;\n else {\n index += 1;\n if (char === quote) return index;\n }\n }\n return value.length;\n }\n\n function findCssFunctionEnd(value, openParenIndex) {\n let index = openParenIndex + 1;\n let depth = 1;\n let quote = \"\";\n while (index < value.length) {\n const char = value[index];\n if (quote) {\n if (char === \"\\\\\\\\\") index += 2;\n else {\n if (char === quote) quote = \"\";\n index += 1;\n }\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n index += 1;\n continue;\n }\n if (cssStartsWithComment(value, index)) {\n const commentEnd = value.indexOf(\"*/\", index + 2);\n index = commentEnd === -1 ? value.length : commentEnd + 2;\n continue;\n }\n if (char === \"(\") depth += 1;\n else if (char === \")\") {\n depth -= 1;\n if (depth === 0) return index + 1;\n }\n index += 1;\n }\n return value.length;\n }\n\n function findFontShorthandFamilyStart(value) {\n const tokens = readCssValueTokens(value);\n for (let index = 0; index < tokens.length; index += 1) {\n const token = tokens[index];\n if (!token || !isFontSizeToken(token.text)) continue;\n if (findTopLevelSlash(token.text) !== -1) return token.end;\n const slashIndex = skipCssWhitespaceAndComments(value, token.end);\n if (value[slashIndex] !== \"/\") return token.end;\n const lineHeightStart = skipCssWhitespaceAndComments(value, slashIndex + 1);\n const lineHeightToken = tokens.find((candidate) => candidate.start >= lineHeightStart);\n return lineHeightToken ? lineHeightToken.end : token.end;\n }\n return -1;\n }\n\n function readCssValueTokens(value) {\n const tokens = [];\n let index = 0;\n while (index < value.length) {\n if (/\\\\s/.test(value[index] ?? \"\")) {\n index += 1;\n continue;\n }\n if (cssStartsWithComment(value, index)) {\n const commentEnd = value.indexOf(\"*/\", index + 2);\n index = commentEnd === -1 ? value.length : commentEnd + 2;\n continue;\n }\n const start = index;\n const char = value[index];\n if (char === '\"' || char === \"'\") {\n index = findCssStringEnd(value, index);\n } else {\n let parenDepth = 0;\n while (index < value.length) {\n if (cssStartsWithComment(value, index)) {\n if (parenDepth === 0) break;\n const commentEnd = value.indexOf(\"*/\", index + 2);\n index = commentEnd === -1 ? value.length : commentEnd + 2;\n continue;\n }\n const tokenChar = value[index];\n if ((tokenChar === '\"' || tokenChar === \"'\") && parenDepth > 0) {\n index = findCssStringEnd(value, index);\n continue;\n }\n if (tokenChar === \"(\") parenDepth += 1;\n else if (tokenChar === \")\") parenDepth = Math.max(0, parenDepth - 1);\n if (parenDepth === 0 && /\\\\s/.test(tokenChar ?? \"\")) break;\n index += 1;\n }\n }\n tokens.push({ start, end: index, text: value.slice(start, index) });\n }\n return tokens;\n }\n\n function isFontSizeToken(token) {\n const slashIndex = findTopLevelSlash(token);\n const sizeToken = slashIndex === -1 ? token : token.slice(0, slashIndex);\n return /^(?:xx-small|x-small|small|medium|large|x-large|xx-large|xxx-large|smaller|larger|math|(?:\\\\d+|\\\\d*\\\\.\\\\d+)(?:px|em|rem|%|vh|vw|vmin|vmax|ch|ex|cap|ic|lh|rlh|cm|mm|q|in|pc|pt))$/i.test(sizeToken) || isFontSizeFunctionToken(sizeToken);\n }\n\n function isFontSizeFunctionToken(token) {\n return /^(?:calc|clamp|min|max|var|env|abs|sign|round|mod|rem|sin|cos|tan|asin|acos|atan|atan2|pow|sqrt|hypot|log|exp)\\\\(/i.test(token);\n }\n\n function findTopLevelSlash(value) {\n let index = 0;\n let quote = \"\";\n let parenDepth = 0;\n while (index < value.length) {\n const char = value[index];\n if (quote) {\n if (char === \"\\\\\\\\\") index += 2;\n else {\n if (char === quote) quote = \"\";\n index += 1;\n }\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n index += 1;\n continue;\n }\n if (char === \"(\") parenDepth += 1;\n else if (char === \")\") parenDepth = Math.max(0, parenDepth - 1);\n else if (char === \"/\" && parenDepth === 0) return index;\n index += 1;\n }\n return -1;\n }\n\n function skipCssWhitespaceAndComments(value, startIndex) {\n let index = startIndex;\n while (index < value.length) {\n if (/\\\\s/.test(value[index] ?? \"\")) {\n index += 1;\n continue;\n }\n if (cssStartsWithComment(value, index)) {\n const commentEnd = value.indexOf(\"*/\", index + 2);\n index = commentEnd === -1 ? value.length : commentEnd + 2;\n continue;\n }\n return index;\n }\n return index;\n }\n\n function cssStartsWithComment(value, index) {\n return value[index] === \"/\" && value[index + 1] === \"*\";\n }\n\n function isCssUrlFunctionStart(value, index) {\n return /^url\\\\s*\\\\(/i.test(value.slice(index)) && !/[A-Za-z0-9_-]/.test(value[index - 1] ?? \"\");\n }\n\n function stripCssComments(value) {\n return value.replace(/\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\//g, \"\");\n }\n\n function splitCssCommaList(value) {\n const parts = [];\n let current = \"\";\n let quote = \"\";\n let parenDepth = 0;\n for (let index = 0; index < value.length; index += 1) {\n const char = value[index];\n if (quote) {\n current += char;\n if (char === \"\\\\\\\\\") {\n index += 1;\n current += value[index] ?? \"\";\n } else if (char === quote) quote = \"\";\n continue;\n }\n if (char === '\"' || char === \"'\") {\n quote = char;\n current += char;\n continue;\n }\n if (char === \"(\") parenDepth += 1;\n else if (char === \")\") parenDepth = Math.max(0, parenDepth - 1);\n if (char === \",\" && parenDepth === 0) {\n parts.push(current);\n current = \"\";\n } else current += char;\n }\n parts.push(current);\n return parts;\n }\n\n function escapeRegExp(value) {\n return value.replace(/[.*+?^${\"$\"}{}()|[\\\\]\\\\\\\\]/g, \"\\\\\\\\$&\");\n }\n\n function encodeCssIdentifier(value) {\n return Array.from(value, (char) => char.codePointAt(0)?.toString(16).padStart(2, \"0\") ?? \"00\").join(\"_\");\n }\n\n return {\n${configFileSource} publicDir: false,\n resolve: {\n conditions: [\"fluid-widget-authoring\"],\n },\n plugins: [fluidWidgetBuildInvariantsPlugin(), fluidWidgetCssIsolationPlugin()],\n build: createFluidWidgetBuildInvariants(),\n };\n})()`;\n}\n\nasync function validateWidgetPackageOutputPaths(\n projectDir: string,\n publishDir: string,\n): Promise<void> {\n validateSharedWidgetPackagePublishDir(projectDir, publishDir);\n await rejectSymlinkedPathSegments({\n projectDir,\n relativePath: publishDir,\n label: \"publishDir\",\n });\n await rejectSymlinkedPathSegments({\n projectDir,\n relativePath: TEMP_BUILD_DIR,\n label: \"reserved temporary build directory\",\n });\n}\n\nasync function collectCssUrls(publishDir: string): Promise<string[]> {\n const entries = await fs.readdir(publishDir, { withFileTypes: true });\n return entries\n .filter(\n (entry) => entry.isFile() && isWidgetPackageCssArtifactPath(entry.name),\n )\n .map((entry) => entry.name)\n .sort();\n}\n\nasync function rejectSymlinkedPathSegments(options: {\n readonly projectDir: string;\n readonly relativePath: string;\n readonly label: string;\n}): Promise<void> {\n const resolvedProjectDir = path.resolve(options.projectDir);\n const resolvedTargetPath = path.resolve(\n resolvedProjectDir,\n options.relativePath,\n );\n const relative = path.relative(resolvedProjectDir, resolvedTargetPath);\n const segments = relative.split(path.sep).filter(Boolean);\n let currentPath = resolvedProjectDir;\n\n for (const segment of segments) {\n currentPath = path.join(currentPath, segment);\n let stat: fs.Stats;\n try {\n stat = await fs.lstat(currentPath);\n } catch (err) {\n if (isNodeError(err) && err.code === \"ENOENT\") return;\n throw err;\n }\n\n if (stat.isSymbolicLink()) {\n throw new Error(`${options.label} must not include symbolic links.`);\n }\n }\n}\n\nfunction normalizePublishDirForValidation(value: string): string {\n return toPosixPath(path.normalize(value)).replace(/\\/+$/, \"\") || \".\";\n}\n\nfunction isPathWithinReservedDir(value: string, reservedDir: string): boolean {\n return value === reservedDir || value.startsWith(`${reservedDir}/`);\n}\n\nfunction toPosixPath(value: string): string {\n return value.split(path.sep).join(\"/\");\n}\n\nfunction stableStringify(value: unknown): string {\n return `${JSON.stringify(value, null, 2)}\\n`;\n}\n\nfunction readCliVersion(): string {\n const startDir = path.dirname(fileURLToPath(import.meta.url));\n for (const packageJsonPath of candidatePackageJsonPaths(startDir)) {\n try {\n const packageJson = require(packageJsonPath) as {\n name?: unknown;\n version?: unknown;\n };\n if (\n packageJson.name === \"@fluid-app/fluid-cli-portal\" &&\n typeof packageJson.version === \"string\"\n ) {\n return packageJson.version;\n }\n } catch {\n // Keep walking upward until the package root is found.\n }\n }\n\n return \"0.0.0\";\n}\n\nfunction resolveViteCliPathFromRequire(\n moduleRequire: NodeJS.Require,\n): string | undefined {\n try {\n const packageJsonPath = moduleRequire.resolve(\"vite/package.json\");\n const packageJson = moduleRequire(packageJsonPath) as { bin?: unknown };\n const binPath = getViteBinPath(packageJson.bin);\n if (!binPath) return undefined;\n\n return path.resolve(path.dirname(packageJsonPath), binPath);\n } catch (err) {\n if (isModuleResolutionError(err)) return undefined;\n throw err;\n }\n}\n\nfunction getViteBinPath(bin: unknown): string | undefined {\n if (typeof bin === \"string\") return bin;\n if (!isRecord(bin)) return undefined;\n\n const viteBin = bin.vite;\n return typeof viteBin === \"string\" ? viteBin : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isNodeError(value: unknown): value is NodeJS.ErrnoException {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"code\" in value &&\n typeof value.code === \"string\"\n );\n}\n\nfunction isModuleResolutionError(value: unknown): boolean {\n return (\n isNodeError(value) &&\n (value.code === \"MODULE_NOT_FOUND\" || value.code === \"ERR_MODULE_NOT_FOUND\")\n );\n}\n\nfunction candidatePackageJsonPaths(startDir: string): string[] {\n const paths: string[] = [];\n let current = startDir;\n\n while (true) {\n paths.push(path.join(current, \"package.json\"));\n const parent = path.dirname(current);\n if (parent === current) return paths;\n current = parent;\n }\n}\n","/**\n * Shared widget package publish/upload helpers.\n *\n * These utilities cover the two owner scopes currently supported by the\n * portal widget package upload API: marketplace droplets and company-owned\n * Fluid OS packages. They intentionally do not register CLI commands; command\n * implementations can compose the typed payload builders, session/complete\n * requests, signed URL uploads, and dry-run orchestration exposed here.\n */\n\nimport type { FetchClient } from \"@fluid-app/fluid-cli\";\nimport { fluidOs } from \"@fluid-app/fluidos-api-client\";\nimport type { ArtifactMetadata } from \"./widget-package-artifacts.js\";\n\nexport type WidgetPackageUploadOwner =\n | { readonly kind: \"droplet\"; readonly uuid: string }\n | { readonly kind: \"company\" };\n\nexport type WidgetPackageArtifactMetadata = ArtifactMetadata;\n\nexport interface WidgetPackageUploadArtifact extends WidgetPackageArtifactMetadata {\n readonly body: BodyInit;\n}\n\nexport interface WidgetPackageSessionRequest {\n readonly version: string;\n readonly packageKey: string;\n readonly builderVersion: string;\n readonly cliVersion: string;\n readonly runtimeVersion: string;\n readonly manifestHash: string;\n readonly manifest: Record<string, unknown>;\n readonly artifacts: readonly WidgetPackageArtifactMetadata[];\n}\n\nexport interface WidgetPackagePublishRequest extends Omit<\n WidgetPackageSessionRequest,\n \"artifacts\"\n> {\n readonly artifacts: readonly WidgetPackageUploadArtifact[];\n}\n\nexport type WidgetPackageArtifactPayload = ArtifactMetadata;\n\nexport interface WidgetPackageUploadSessionPayload {\n readonly version: string;\n readonly package_key: string;\n readonly builder_version: string;\n readonly cli_version: string;\n readonly runtime_version: string;\n readonly manifest_hash: string;\n readonly manifest: Record<string, unknown>;\n readonly artifacts: readonly WidgetPackageArtifactPayload[];\n}\n\nexport interface WidgetPackageCompleteUploadPayload {\n readonly package_key: string;\n readonly artifacts: readonly WidgetPackageArtifactPayload[];\n}\n\nexport interface WidgetPackageSignedUpload {\n readonly path: string;\n readonly url: string;\n readonly contentType: string;\n readonly headers: Readonly<Record<string, string>>;\n}\n\nexport interface WidgetPackageUploadSession {\n readonly version: string;\n readonly uploads: readonly WidgetPackageSignedUpload[];\n readonly raw: unknown;\n}\n\nexport interface WidgetPackageArtifactUploadResult {\n readonly path: string;\n readonly status: number;\n readonly contentType: string;\n}\n\nexport interface WidgetPackageCompleteResult {\n readonly version: string;\n readonly status?: string;\n readonly packageKey?: string;\n readonly raw: unknown;\n}\n\nexport interface WidgetPackagePublishResult {\n readonly dryRun: boolean;\n readonly sessionPayload: WidgetPackageUploadSessionPayload;\n readonly session?: WidgetPackageUploadSession;\n readonly uploadedArtifacts?: readonly WidgetPackageArtifactUploadResult[];\n readonly complete?: WidgetPackageCompleteResult;\n}\n\ninterface BasePublishWidgetPackageVersionOptions {\n readonly owner: WidgetPackageUploadOwner;\n readonly request: WidgetPackagePublishRequest;\n readonly fetchImpl?: WidgetPackageUploadFetch;\n}\n\nexport interface DryRunPublishWidgetPackageVersionOptions extends BasePublishWidgetPackageVersionOptions {\n readonly client?: FetchClient;\n readonly dryRun: true;\n}\n\nexport interface PublishWidgetPackageVersionUploadOptions extends BasePublishWidgetPackageVersionOptions {\n readonly client: FetchClient;\n readonly dryRun?: boolean;\n}\n\nexport type PublishWidgetPackageVersionOptions =\n | DryRunPublishWidgetPackageVersionOptions\n | PublishWidgetPackageVersionUploadOptions;\n\ntype FluidOsCreateWidgetPackageVersionPayload = Parameters<\n typeof fluidOs.fluid_os_v0_create_widget_package_version\n>[1];\n\ntype FluidOsCompleteWidgetPackageVersionUploadPayload = NonNullable<\n Parameters<\n typeof fluidOs.fluid_os_v0_complete_widget_package_version_upload\n >[2]\n>;\n\nexport type WidgetPackageUploadFetch = (\n input: string | URL,\n init: RequestInit,\n) => Promise<Response>;\n\nexport class WidgetPackageUploadError extends Error {\n public readonly code: string;\n\n constructor(code: string, message: string) {\n super(message);\n this.name = \"WidgetPackageUploadError\";\n this.code = code;\n }\n}\n\nconst SESSION_ARRAY_KEYS = [\n \"uploads\",\n \"artifacts\",\n \"signedUploads\",\n \"signed_uploads\",\n \"signedUrls\",\n \"signed_urls\",\n \"uploadUrls\",\n \"upload_urls\",\n] as const;\n\nconst SESSION_RECORD_KEYS = [\n \"signedUrls\",\n \"signed_urls\",\n \"uploadUrls\",\n \"upload_urls\",\n] as const;\n\nexport function buildWidgetPackageArtifactPayload(\n artifact: WidgetPackageArtifactMetadata,\n): WidgetPackageArtifactPayload {\n return {\n path: artifact.path,\n sha256: artifact.sha256,\n bytes: artifact.bytes,\n contentType: artifact.contentType,\n };\n}\n\nexport function buildWidgetPackageUploadSessionPayload(\n request: WidgetPackageSessionRequest,\n): WidgetPackageUploadSessionPayload {\n return {\n version: request.version,\n package_key: request.packageKey,\n builder_version: request.builderVersion,\n cli_version: request.cliVersion,\n runtime_version: request.runtimeVersion,\n manifest_hash: request.manifestHash,\n manifest: request.manifest,\n artifacts: request.artifacts.map(buildWidgetPackageArtifactPayload),\n };\n}\n\nexport function buildWidgetPackageCompleteUploadPayload(\n packageKey: string,\n artifacts: readonly WidgetPackageArtifactMetadata[],\n): WidgetPackageCompleteUploadPayload {\n return {\n package_key: packageKey,\n artifacts: artifacts.map(buildWidgetPackageArtifactPayload),\n };\n}\n\nexport function getWidgetPackageUploadSessionRoute(\n owner: WidgetPackageUploadOwner,\n): string {\n switch (owner.kind) {\n case \"droplet\":\n return `/api/droplets/${encodeURIComponent(owner.uuid)}/widget_package_versions`;\n case \"company\":\n return \"/api/company/fluid_os/widget_package_versions\";\n }\n}\n\nexport function getWidgetPackageCompleteUploadRoute(\n owner: WidgetPackageUploadOwner,\n version: string,\n): string {\n switch (owner.kind) {\n case \"droplet\":\n return `/api/droplets/${encodeURIComponent(owner.uuid)}/widget_package_versions/${encodeURIComponent(version)}/complete_upload`;\n case \"company\":\n return `/api/company/fluid_os/widget_package_versions/${encodeURIComponent(version)}/complete_upload`;\n }\n}\n\nexport async function requestWidgetPackageUploadSession(\n client: FetchClient,\n owner: WidgetPackageUploadOwner,\n request: WidgetPackageSessionRequest,\n): Promise<WidgetPackageUploadSession> {\n const payload = buildWidgetPackageUploadSessionPayload(request);\n\n try {\n const response =\n owner.kind === \"company\"\n ? await fluidOs.fluid_os_v0_create_widget_package_version(\n client,\n payload as FluidOsCreateWidgetPackageVersionPayload,\n )\n : await client.post<unknown>(\n getWidgetPackageUploadSessionRoute(owner),\n payload,\n );\n return normalizeWidgetPackageUploadSession(\n response,\n request.version,\n request.artifacts,\n );\n } catch (err) {\n if (err instanceof WidgetPackageUploadError) {\n throw err;\n }\n\n throw new WidgetPackageUploadError(\n \"SESSION_REQUEST_FAILED\",\n `Failed to create widget package upload session: ${formatUnknownError(err)}`,\n );\n }\n}\n\nexport async function uploadWidgetPackageArtifacts(\n session: WidgetPackageUploadSession,\n artifacts: readonly WidgetPackageUploadArtifact[],\n fetchImpl: WidgetPackageUploadFetch = fetch,\n): Promise<WidgetPackageArtifactUploadResult[]> {\n const uploadsByPath = new Map(\n session.uploads.map((upload) => [upload.path, upload] as const),\n );\n const results: WidgetPackageArtifactUploadResult[] = [];\n\n for (const artifact of artifacts) {\n const upload = uploadsByPath.get(artifact.path);\n if (!upload) {\n throw new WidgetPackageUploadError(\n \"MISSING_SIGNED_URL\",\n `Upload session did not include a signed URL for artifact \"${artifact.path}\".`,\n );\n }\n\n if (upload.contentType !== artifact.contentType) {\n throw new WidgetPackageUploadError(\n \"CONTENT_TYPE_MISMATCH\",\n `Upload session expected artifact \"${artifact.path}\" to use content type \"${upload.contentType}\", but local artifact uses \"${artifact.contentType}\".`,\n );\n }\n\n let response: Response;\n try {\n response = await fetchImpl(upload.url, {\n method: \"PUT\",\n headers: mergeUploadHeaders(upload.headers, upload.contentType),\n body: artifact.body,\n });\n } catch (err) {\n throw new WidgetPackageUploadError(\n \"ARTIFACT_UPLOAD_FAILED\",\n `Failed to upload artifact \"${artifact.path}\": ${formatUnknownError(err)}`,\n );\n }\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n const details = body.trim() ? `: ${body.trim().slice(0, 500)}` : \"\";\n throw new WidgetPackageUploadError(\n \"ARTIFACT_UPLOAD_FAILED\",\n `Failed to upload artifact \"${artifact.path}\": PUT returned HTTP ${response.status}${details}`,\n );\n }\n\n results.push({\n path: artifact.path,\n status: response.status,\n contentType: upload.contentType,\n });\n }\n\n return results;\n}\n\nexport async function completeWidgetPackageUpload(\n client: FetchClient,\n owner: WidgetPackageUploadOwner,\n version: string,\n packageKey: string,\n artifacts: readonly WidgetPackageArtifactMetadata[],\n): Promise<WidgetPackageCompleteResult> {\n const payload = buildWidgetPackageCompleteUploadPayload(\n packageKey,\n artifacts,\n );\n\n try {\n const response =\n owner.kind === \"company\"\n ? await fluidOs.fluid_os_v0_complete_widget_package_version_upload(\n client,\n version,\n payload as FluidOsCompleteWidgetPackageVersionUploadPayload,\n )\n : await client.post<unknown>(\n getWidgetPackageCompleteUploadRoute(owner, version),\n payload,\n );\n return normalizeWidgetPackageCompleteResponse(response, version);\n } catch (err) {\n if (err instanceof WidgetPackageUploadError) {\n throw err;\n }\n\n throw new WidgetPackageUploadError(\n \"COMPLETE_UPLOAD_FAILED\",\n `Failed to complete widget package upload: ${formatUnknownError(err)}`,\n );\n }\n}\n\nexport async function publishWidgetPackageVersion(\n options: PublishWidgetPackageVersionOptions,\n): Promise<WidgetPackagePublishResult> {\n const sessionPayload = buildWidgetPackageUploadSessionPayload(\n options.request,\n );\n\n if (options.dryRun) {\n return { dryRun: true, sessionPayload };\n }\n\n if (!options.client) {\n throw new Error(\"A FetchClient is required when dryRun is false.\");\n }\n\n const session = await requestWidgetPackageUploadSession(\n options.client,\n options.owner,\n options.request,\n );\n const uploadedArtifacts = await uploadWidgetPackageArtifacts(\n session,\n options.request.artifacts,\n options.fetchImpl,\n );\n const complete = await completeWidgetPackageUpload(\n options.client,\n options.owner,\n session.version,\n options.request.packageKey,\n options.request.artifacts,\n );\n\n return {\n dryRun: false,\n sessionPayload,\n session,\n uploadedArtifacts,\n complete,\n };\n}\n\nexport function normalizeWidgetPackageUploadSession(\n response: unknown,\n requestedVersion: string,\n requestedArtifacts: readonly WidgetPackageArtifactMetadata[],\n): WidgetPackageUploadSession {\n const record = requireRecord(\n response,\n \"Upload session response must be a JSON object.\",\n );\n const responseVersion = getResponseVersion(record);\n\n if (responseVersion && responseVersion !== requestedVersion) {\n throw new WidgetPackageUploadError(\n \"INVALID_SESSION_RESPONSE\",\n `Upload session response version \"${responseVersion}\" did not match requested version \"${requestedVersion}\".`,\n );\n }\n\n const version = responseVersion ?? requestedVersion;\n const nestedRecord = getNestedVersionRecord(record);\n const uploadRecords = nestedRecord ? [record, nestedRecord] : [record];\n const uploads = getSignedUploads(uploadRecords, requestedArtifacts);\n const missingUploadPaths = requestedArtifacts\n .map((artifact) => artifact.path)\n .filter(\n (artifactPath) => !uploads.some((upload) => upload.path === artifactPath),\n );\n\n if (missingUploadPaths.length > 0) {\n throw new WidgetPackageUploadError(\n \"INVALID_SESSION_RESPONSE\",\n `Upload session response is missing signed URLs for artifact(s): ${missingUploadPaths.join(\", \")}.`,\n );\n }\n\n return { version, uploads, raw: response };\n}\n\nexport function normalizeWidgetPackageCompleteResponse(\n response: unknown,\n requestedVersion: string,\n): WidgetPackageCompleteResult {\n if (response == null) {\n return { version: requestedVersion, raw: response };\n }\n\n const record = requireRecord(\n response,\n \"Complete upload response must be a JSON object or empty response.\",\n );\n const nested = getNestedVersionRecord(record) ?? record;\n const responseVersion = getResponseVersion(nested);\n\n if (responseVersion && responseVersion !== requestedVersion) {\n throw new WidgetPackageUploadError(\n \"INVALID_COMPLETE_RESPONSE\",\n `Complete upload response version \"${responseVersion}\" did not match requested version \"${requestedVersion}\".`,\n );\n }\n\n const packageKey =\n getStringProperty(nested, \"package_key\") ??\n getStringProperty(nested, \"packageKey\") ??\n getStringProperty(nested, \"packageId\");\n const status =\n getStringProperty(nested, \"status\") ?? getStringProperty(nested, \"state\");\n\n return {\n version: responseVersion ?? requestedVersion,\n ...(status ? { status } : {}),\n ...(packageKey ? { packageKey } : {}),\n raw: response,\n };\n}\n\nfunction getSignedUploads(\n records: readonly Record<string, unknown>[],\n requestedArtifacts: readonly WidgetPackageArtifactMetadata[],\n): WidgetPackageSignedUpload[] {\n const uploads: WidgetPackageSignedUpload[] = [];\n\n for (const record of records) {\n for (const key of SESSION_ARRAY_KEYS) {\n const value = record[key];\n if (!Array.isArray(value)) continue;\n\n for (const item of value) {\n const upload = signedUploadFromRecord(item, requestedArtifacts);\n if (upload) uploads.push(upload);\n }\n }\n\n for (const key of SESSION_RECORD_KEYS) {\n const value = record[key];\n if (!isRecord(value) || Array.isArray(value)) continue;\n\n for (const [artifactPath, uploadValue] of Object.entries(value)) {\n const upload = signedUploadFromKeyedValue(\n artifactPath,\n uploadValue,\n requestedArtifacts,\n );\n if (upload) uploads.push(upload);\n }\n }\n }\n\n return dedupeUploads(uploads);\n}\n\nfunction signedUploadFromRecord(\n value: unknown,\n requestedArtifacts: readonly WidgetPackageArtifactMetadata[],\n): WidgetPackageSignedUpload | null {\n if (!isRecord(value)) return null;\n\n const artifactPath = readFirstString(value, [\n \"path\",\n \"key\",\n \"artifactPath\",\n \"artifact_path\",\n \"artifactKey\",\n \"artifact_key\",\n \"name\",\n ]);\n const url = readFirstString(value, [\n \"url\",\n \"signedUrl\",\n \"signed_url\",\n \"uploadUrl\",\n \"upload_url\",\n ]);\n if (!artifactPath || !url) return null;\n\n const requestedArtifact = findRequestedArtifact(\n requestedArtifacts,\n artifactPath,\n );\n const contentType =\n readFirstString(value, [\n \"contentType\",\n \"content_type\",\n \"expectedContentType\",\n \"expected_content_type\",\n ]) ?? requestedArtifact?.contentType;\n\n if (!contentType) return null;\n\n return {\n path: artifactPath,\n url,\n contentType,\n headers: getHeaders(value[\"headers\"]),\n };\n}\n\nfunction signedUploadFromKeyedValue(\n artifactPath: string,\n value: unknown,\n requestedArtifacts: readonly WidgetPackageArtifactMetadata[],\n): WidgetPackageSignedUpload | null {\n const requestedArtifact = findRequestedArtifact(\n requestedArtifacts,\n artifactPath,\n );\n\n if (typeof value === \"string\") {\n if (!requestedArtifact) return null;\n return {\n path: artifactPath,\n url: value,\n contentType: requestedArtifact.contentType,\n headers: {},\n };\n }\n\n if (!isRecord(value)) return null;\n\n const url = readFirstString(value, [\n \"url\",\n \"signedUrl\",\n \"signed_url\",\n \"uploadUrl\",\n \"upload_url\",\n ]);\n if (!url) return null;\n\n const contentType =\n readFirstString(value, [\n \"contentType\",\n \"content_type\",\n \"expectedContentType\",\n \"expected_content_type\",\n ]) ?? requestedArtifact?.contentType;\n\n if (!contentType) return null;\n\n return {\n path: artifactPath,\n url,\n contentType,\n headers: getHeaders(value[\"headers\"]),\n };\n}\n\nfunction normalizeHeaderName(name: string): string {\n return name.toLowerCase();\n}\n\nfunction mergeUploadHeaders(\n headers: Readonly<Record<string, string>>,\n contentType: string,\n): Record<string, string> {\n const merged: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(headers)) {\n if (normalizeHeaderName(key) === \"content-type\") continue;\n merged[key] = value;\n }\n\n merged[\"Content-Type\"] = contentType;\n return merged;\n}\n\nfunction dedupeUploads(\n uploads: readonly WidgetPackageSignedUpload[],\n): WidgetPackageSignedUpload[] {\n const deduped = new Map<string, WidgetPackageSignedUpload>();\n for (const upload of uploads) {\n deduped.set(upload.path, upload);\n }\n return Array.from(deduped.values());\n}\n\nfunction findRequestedArtifact(\n requestedArtifacts: readonly WidgetPackageArtifactMetadata[],\n artifactPath: string,\n): WidgetPackageArtifactMetadata | undefined {\n return requestedArtifacts.find((artifact) => artifact.path === artifactPath);\n}\n\nfunction requireRecord(\n value: unknown,\n message: string,\n): Record<string, unknown> {\n if (!isRecord(value) || Array.isArray(value)) {\n throw new WidgetPackageUploadError(\"INVALID_RESPONSE\", message);\n }\n return value;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction getStringProperty(\n record: Record<string, unknown>,\n key: string,\n): string | undefined {\n const value = record[key];\n if (typeof value === \"string\" && value.trim().length > 0) {\n return value;\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return String(value);\n }\n return undefined;\n}\n\nfunction readFirstString(\n record: Record<string, unknown>,\n keys: readonly string[],\n): string | undefined {\n for (const key of keys) {\n const value = getStringProperty(record, key);\n if (value) return value;\n }\n return undefined;\n}\n\nfunction getHeaders(value: unknown): Record<string, string> {\n if (!isRecord(value) || Array.isArray(value)) return {};\n\n const headers: Record<string, string> = {};\n for (const [key, headerValue] of Object.entries(value)) {\n if (typeof headerValue === \"string\") {\n headers[key] = headerValue;\n }\n }\n return headers;\n}\n\nfunction getResponseVersion(\n record: Record<string, unknown>,\n): string | undefined {\n const directVersion = getStringProperty(record, \"version\");\n if (directVersion) return directVersion;\n\n const nested = getNestedVersionRecord(record);\n return nested ? getStringProperty(nested, \"version\") : undefined;\n}\n\nfunction getNestedVersionRecord(\n record: Record<string, unknown>,\n): Record<string, unknown> | undefined {\n const candidates = [\n record[\"portal_widget_package_version\"],\n record[\"widget_package_version\"],\n record[\"package_version\"],\n ];\n\n for (const candidate of candidates) {\n if (isRecord(candidate) && !Array.isArray(candidate)) {\n return candidate;\n }\n }\n\n return undefined;\n}\n\nfunction formatUnknownError(err: unknown): string {\n const base = err instanceof Error ? err.message : String(err);\n\n if (isRecord(err) && \"data\" in err) {\n return `${base} — ${JSON.stringify(err.data)}`;\n }\n\n return base;\n}\n","import { findProjectConfig, readConfig } from \"@fluid-app/fluid-cli\";\nimport type { FetchClient } from \"@fluid-app/fluid-cli\";\nimport { createFetchClient } from \"@fluid-app/fluidos-api-client\";\nimport chalk from \"chalk\";\nimport fs from \"fs-extra\";\nimport path from \"node:path\";\nimport {\n buildSharedWidgetPackage,\n validateSharedWidgetPackagePublishDir,\n} from \"../utils/widget-package-builder.js\";\nimport type {\n BuildSharedWidgetPackageOptions,\n SharedWidgetPackageBuildResult,\n} from \"../utils/widget-package-builder.js\";\nimport { publishWidgetPackageVersion } from \"../utils/widget-package-upload.js\";\nimport type {\n WidgetPackagePublishRequest,\n WidgetPackagePublishResult,\n WidgetPackageUploadOwner,\n} from \"../utils/widget-package-upload.js\";\nimport {\n collectWidgetPackageArtifacts,\n computeArtifactMetadata,\n sha256,\n type ArtifactMetadata,\n type PublishManifestMetadata,\n} from \"../utils/widget-package-artifacts.js\";\nimport type { WidgetPackageOwnerKind as WidgetPackageBuildOwner } from \"../utils/widget-package-validation.js\";\n\nexport interface PublishWidgetRuntimeArtifactsOptions {\n readonly projectDir: string;\n readonly outDir: string;\n readonly buildOwner: WidgetPackageBuildOwner;\n readonly uploadOwner: WidgetPackageUploadOwner;\n readonly dryRun?: boolean;\n readonly client?: FetchClient;\n}\n\nexport interface PublishWidgetRuntimeArtifactsResult {\n readonly build: SharedWidgetPackageBuildResult;\n readonly request: WidgetPackagePublishRequest;\n readonly publish: WidgetPackagePublishResult;\n}\n\nexport interface PublishWidgetRuntimeArtifactsDependencies {\n readonly buildSharedWidgetPackage?: typeof buildSharedWidgetPackage;\n readonly publishWidgetPackageVersion?: typeof publishWidgetPackageVersion;\n}\n\nexport async function publishWidgetRuntimeArtifacts(\n options: PublishWidgetRuntimeArtifactsOptions,\n dependencies: PublishWidgetRuntimeArtifactsDependencies = {},\n): Promise<PublishWidgetRuntimeArtifactsResult> {\n const buildPackage =\n dependencies.buildSharedWidgetPackage ?? buildSharedWidgetPackage;\n const publishVersion =\n dependencies.publishWidgetPackageVersion ?? publishWidgetPackageVersion;\n\n const isDryRun = options.dryRun === true;\n const client = options.client;\n\n if (!isDryRun && !client) {\n throw new Error(\"A FetchClient is required when dryRun is false.\");\n }\n\n const safeOutDir = validateWidgetPublishOutDir(\n options.projectDir,\n options.outDir,\n );\n const buildResult = await buildPackage({\n projectDir: options.projectDir,\n publishDir: safeOutDir,\n owner: options.buildOwner,\n } satisfies BuildSharedWidgetPackageOptions);\n\n if (!buildResult.success) {\n const details = buildResult.error.details\n ? `\\n${buildResult.error.details}`\n : \"\";\n throw new Error(`${buildResult.error.message}${details}`);\n }\n\n const request = await createWidgetPackagePublishRequest({\n publishDir: buildResult.value.publishDir,\n manifestPath: buildResult.value.manifestPath,\n publishManifestPath: buildResult.value.publishManifestPath,\n owner: options.buildOwner,\n });\n\n let publish: WidgetPackagePublishResult;\n if (isDryRun) {\n publish = await publishVersion({\n owner: options.uploadOwner,\n request,\n dryRun: true,\n });\n } else {\n if (!client) {\n throw new Error(\"A FetchClient is required when dryRun is false.\");\n }\n\n publish = await publishVersion({\n client,\n owner: options.uploadOwner,\n request,\n });\n }\n\n return { build: buildResult.value, request, publish };\n}\n\nexport async function createWidgetPackagePublishRequest(options: {\n readonly publishDir: string;\n readonly manifestPath: string;\n readonly publishManifestPath: string;\n readonly owner: WidgetPackageBuildOwner;\n}): Promise<WidgetPackagePublishRequest> {\n const manifestContent = await fs.readFile(options.manifestPath);\n const manifest = parseJsonRecord(\n manifestContent.toString(\"utf-8\"),\n options.manifestPath,\n );\n const publishManifest = await readPublishManifest(\n options.publishManifestPath,\n );\n assertManifestIdentityMatches(\n manifest,\n publishManifest,\n options.manifestPath,\n );\n assertMetadataMatches({\n label: \"manifestHash\",\n path: \"manifest.json\",\n expected: publishManifest.manifestHash,\n actual: sha256(manifestContent),\n });\n const collectedArtifacts = await collectWidgetPackageArtifacts(\n options.publishDir,\n );\n assertArtifactInventoryMatches(publishManifest.artifacts, collectedArtifacts);\n const artifacts = await readUploadArtifacts(\n options.publishDir,\n publishManifest.artifacts,\n );\n\n return {\n version: publishManifest.version,\n packageKey: stripOwnerPrefix(publishManifest.packageId, options.owner),\n builderVersion: publishManifest.builderVersion,\n cliVersion: publishManifest.cliVersion,\n runtimeVersion: publishManifest.runtimeVersion,\n manifestHash: publishManifest.manifestHash,\n manifest,\n artifacts,\n };\n}\n\nexport function createAuthenticatedWidgetPackageClient(): FetchClient {\n const { profile, profileName, token } = resolveAuthenticatedProfile();\n if (!token) {\n if (!profileName) {\n throw new Error(\n \"Not logged in. Run \" + chalk.cyan(\"fluid login\") + \" first.\",\n );\n }\n throw new Error(\n \"No auth token found for profile \" +\n chalk.cyan(profileName) +\n \". Run \" +\n chalk.cyan(\"fluid login\") +\n \" to re-authenticate.\",\n );\n }\n\n return createFetchClient({\n baseUrl:\n profile?.baseUrl ??\n process.env[\"FLUID_API_BASE\"] ??\n \"https://api.fluid.app\",\n getAuthToken: () => token,\n });\n}\n\ntype ProfileWithBaseUrl = ReturnType<typeof readConfig>[\"profiles\"][string] & {\n readonly baseUrl?: string;\n};\n\nfunction resolveAuthenticatedProfile(): {\n readonly profile?: ProfileWithBaseUrl;\n readonly profileName?: string;\n readonly token?: string;\n} {\n const config = readConfig();\n const projectConfig = findProjectConfig(process.cwd());\n\n if (projectConfig?.profile) {\n const profile = config.profiles[projectConfig.profile] as\n | ProfileWithBaseUrl\n | undefined;\n if (profile) {\n return {\n profile,\n profileName: projectConfig.profile,\n token: profile.token,\n };\n }\n }\n\n if (!config.activeProfile) return {};\n const profile = config.profiles[config.activeProfile] as\n | ProfileWithBaseUrl\n | undefined;\n if (!profile) return {};\n\n return {\n profile,\n profileName: config.activeProfile,\n token: profile.token,\n };\n}\n\nexport function printWidgetPublishSummary(options: {\n readonly title: string;\n readonly ownerLabel: string;\n readonly environment?: string;\n readonly outDir: string;\n readonly result: PublishWidgetRuntimeArtifactsResult;\n}): void {\n console.log();\n console.log(chalk.green.bold(`${options.title} complete`));\n console.log();\n console.log(chalk.gray(\"Owner: \") + chalk.white(options.ownerLabel));\n if (options.environment) {\n console.log(chalk.gray(\"Environment: \") + chalk.white(options.environment));\n }\n console.log(\n chalk.gray(\"Package: \") + chalk.white(options.result.build.packageId),\n );\n console.log(\n chalk.gray(\"Version: \") + chalk.white(options.result.build.version),\n );\n console.log(chalk.gray(\"Output: \") + chalk.cyan(options.outDir));\n console.log(\n chalk.gray(\"Artifacts: \") +\n chalk.white(String(options.result.request.artifacts.length)),\n );\n console.log();\n}\n\nexport function printRuntimeOnlyNotice(): void {\n console.log(\n chalk.yellow(\n \"This publishes widget runtime artifacts only; it does not deploy the hosted portal shell.\",\n ),\n );\n console.log();\n}\n\nexport function printDryRunSessionPayload(\n result: PublishWidgetRuntimeArtifactsResult,\n): void {\n console.log(chalk.bold(\"Dry-run upload session payload:\"));\n console.log(JSON.stringify(result.publish.sessionPayload, null, 2));\n console.log();\n}\n\nexport function validateWidgetPublishOutDir(\n projectDir: string,\n outDir: string,\n): string {\n validateSharedWidgetPackagePublishDir(projectDir, outDir, {\n optionName: \"--out-dir\",\n });\n\n return outDir;\n}\n\nasync function readJsonRecord(\n filePath: string,\n): Promise<Record<string, unknown>> {\n return parseJsonRecord(await fs.readFile(filePath, \"utf-8\"), filePath);\n}\n\nfunction parseJsonRecord(\n content: string,\n filePath: string,\n): Record<string, unknown> {\n const value = JSON.parse(content) as unknown;\n if (!isRecord(value) || Array.isArray(value)) {\n throw new Error(`${path.basename(filePath)} must contain a JSON object.`);\n }\n return value;\n}\n\nasync function readPublishManifest(\n filePath: string,\n): Promise<PublishManifestMetadata> {\n const record = await readJsonRecord(filePath);\n const artifactsValue = record[\"artifacts\"];\n if (!Array.isArray(artifactsValue)) {\n throw new Error(\"publish-manifest.json must include an artifacts array.\");\n }\n\n return {\n packageId: readRequiredString(record, \"packageId\", filePath),\n version: readRequiredString(record, \"version\", filePath),\n builderVersion: readRequiredString(record, \"builderVersion\", filePath),\n cliVersion: readRequiredString(record, \"cliVersion\", filePath),\n runtimeVersion: readRequiredString(record, \"runtimeVersion\", filePath),\n manifestHash: readRequiredString(record, \"manifestHash\", filePath),\n artifacts: artifactsValue.map((artifact, index) =>\n readArtifactMetadata(artifact, index),\n ),\n };\n}\n\nfunction readArtifactMetadata(value: unknown, index: number): ArtifactMetadata {\n if (!isRecord(value) || Array.isArray(value)) {\n throw new Error(\n `publish-manifest.json artifacts[${index}] must be a JSON object.`,\n );\n }\n\n return {\n path: readRequiredString(value, \"path\", \"publish-manifest.json\"),\n sha256: readRequiredString(value, \"sha256\", \"publish-manifest.json\"),\n bytes: readRequiredNumber(value, \"bytes\", \"publish-manifest.json\"),\n contentType: readRequiredString(\n value,\n \"contentType\",\n \"publish-manifest.json\",\n ),\n };\n}\n\nasync function readUploadArtifacts(\n publishDir: string,\n artifacts: readonly ArtifactMetadata[],\n): Promise<WidgetPackagePublishRequest[\"artifacts\"]> {\n const resolvedPublishDir = path.resolve(publishDir);\n\n return Promise.all(\n artifacts.map(async (artifact) => {\n const artifactPath = resolveArtifactPath(\n resolvedPublishDir,\n artifact.path,\n );\n const actual = await computeArtifactMetadata(\n artifactPath,\n resolvedPublishDir,\n );\n assertArtifactMetadataMatches(artifact, actual);\n\n return {\n ...actual,\n body: await fs.readFile(artifactPath),\n };\n }),\n );\n}\n\nfunction assertManifestIdentityMatches(\n manifest: Record<string, unknown>,\n publishManifest: PublishManifestMetadata,\n manifestPath: string,\n): void {\n assertMetadataMatches({\n label: \"packageId\",\n path: \"manifest.json\",\n expected: publishManifest.packageId,\n actual: readRequiredString(manifest, \"packageId\", manifestPath),\n });\n assertMetadataMatches({\n label: \"version\",\n path: \"manifest.json\",\n expected: publishManifest.version,\n actual: readRequiredString(manifest, \"version\", manifestPath),\n });\n}\n\nfunction assertArtifactInventoryMatches(\n expected: readonly ArtifactMetadata[],\n actual: readonly ArtifactMetadata[],\n): void {\n const expectedByPath = new Map<string, ArtifactMetadata>();\n for (const artifact of expected) {\n if (expectedByPath.has(artifact.path)) {\n throw new Error(\n `publish-manifest.json artifacts include duplicate path ${JSON.stringify(artifact.path)}. ` +\n \"Rebuild the widget package before publishing.\",\n );\n }\n expectedByPath.set(artifact.path, artifact);\n }\n\n const actualPaths = new Set<string>();\n for (const actualArtifact of actual) {\n actualPaths.add(actualArtifact.path);\n const expectedArtifact = expectedByPath.get(actualArtifact.path);\n if (!expectedArtifact) {\n throw new Error(\n `publish-manifest.json artifacts omit ${JSON.stringify(actualArtifact.path)}. ` +\n \"Rebuild the widget package before publishing.\",\n );\n }\n assertArtifactMetadataMatches(expectedArtifact, actualArtifact);\n }\n\n for (const expectedArtifact of expected) {\n if (actualPaths.has(expectedArtifact.path)) continue;\n throw new Error(\n `publish-manifest.json artifacts include ${JSON.stringify(expectedArtifact.path)}, but that file is not present on disk. ` +\n \"Rebuild the widget package before publishing.\",\n );\n }\n}\n\nfunction assertArtifactMetadataMatches(\n expected: ArtifactMetadata,\n actual: ArtifactMetadata,\n): void {\n assertMetadataMatches({\n label: \"path\",\n path: expected.path,\n expected: expected.path,\n actual: actual.path,\n });\n assertMetadataMatches({\n label: \"sha256\",\n path: expected.path,\n expected: expected.sha256,\n actual: actual.sha256,\n });\n assertMetadataMatches({\n label: \"bytes\",\n path: expected.path,\n expected: expected.bytes,\n actual: actual.bytes,\n });\n assertMetadataMatches({\n label: \"contentType\",\n path: expected.path,\n expected: expected.contentType,\n actual: actual.contentType,\n });\n}\n\nfunction assertMetadataMatches(options: {\n readonly label: string;\n readonly path: string;\n readonly expected: string | number;\n readonly actual: string | number;\n}): void {\n if (options.expected === options.actual) return;\n\n throw new Error(\n `publish-manifest.json ${options.label} for ${JSON.stringify(options.path)} does not match the file on disk. ` +\n `Recorded ${JSON.stringify(options.expected)}, computed ${JSON.stringify(options.actual)}. ` +\n \"Rebuild the widget package before publishing.\",\n );\n}\n\nfunction resolveArtifactPath(publishDir: string, artifactPath: string): string {\n const resolved = path.resolve(publishDir, artifactPath);\n const relative = path.relative(publishDir, resolved);\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) {\n throw new Error(\n `Artifact path ${JSON.stringify(artifactPath)} escapes the publish directory.`,\n );\n }\n return resolved;\n}\n\nfunction stripOwnerPrefix(\n packageId: string,\n owner: WidgetPackageBuildOwner,\n): string {\n const prefix = `${owner}.`;\n if (packageId.startsWith(prefix) && packageId.length > prefix.length) {\n return packageId.slice(prefix.length);\n }\n return packageId;\n}\n\nfunction readRequiredString(\n record: Record<string, unknown>,\n key: string,\n filePath: string,\n): string {\n const value = record[key];\n if (typeof value === \"string\" && value.trim().length > 0) return value;\n throw new Error(`${path.basename(filePath)} must include string ${key}.`);\n}\n\nfunction readRequiredNumber(\n record: Record<string, unknown>,\n key: string,\n filePath: string,\n): number {\n const value = record[key];\n if (typeof value === \"number\" && Number.isFinite(value)) return value;\n throw new Error(`${path.basename(filePath)} must include number ${key}.`);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n","import { Command } from \"commander\";\nimport type { PluginContext } from \"@fluid-app/fluid-cli\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport type { PortalDeployOptions } from \"../types.js\";\nimport {\n createAuthenticatedWidgetPackageClient,\n printRuntimeOnlyNotice,\n printDryRunSessionPayload,\n printWidgetPublishSummary,\n publishWidgetRuntimeArtifacts,\n} from \"./widget-package-publish.js\";\n\nconst DEFAULT_OUT_DIR = \".fluid/widget-dist\";\nconst DEFAULT_ENVIRONMENT = \"production\";\n\nexport const deployCommand: Command = new Command(\"deploy\")\n .description(\"Publish company-owned portal widget runtime artifacts\")\n .option(\n \"-e, --environment <name>\",\n \"Target environment label for output reporting\",\n DEFAULT_ENVIRONMENT,\n )\n .option(\n \"-o, --out-dir <dir>\",\n \"Widget artifact output directory\",\n DEFAULT_OUT_DIR,\n )\n .option(\"--dry-run\", \"Build and validate upload payload without publishing\")\n .action(async (options: PortalDeployOptions) => {\n const environment = options.environment ?? DEFAULT_ENVIRONMENT;\n const outDir = options.outDir ?? DEFAULT_OUT_DIR;\n const dryRun = options.dryRun === true;\n\n console.log();\n console.log(chalk.blue.bold(\"Fluid Portal Deploy\"));\n console.log();\n printRuntimeOnlyNotice();\n console.log(chalk.gray(\"Environment: \") + chalk.white(environment));\n console.log(chalk.gray(\"Output: \") + chalk.cyan(outDir));\n if (dryRun)\n console.log(chalk.yellow(\"Dry run: no upload will be created.\"));\n console.log();\n\n const spinner = ora(\"Building company-owned widget package...\").start();\n\n try {\n const result = await publishWidgetRuntimeArtifacts({\n projectDir: process.cwd(),\n outDir,\n buildOwner: \"company\",\n uploadOwner: { kind: \"company\" },\n dryRun,\n ...(dryRun ? {} : { client: createAuthenticatedWidgetPackageClient() }),\n });\n\n spinner.succeed(\"Built widget runtime artifacts\");\n\n if (dryRun) {\n console.log(\n chalk.yellow(\"Dry run complete — upload session was not requested.\"),\n );\n console.log();\n printDryRunSessionPayload(result);\n } else {\n console.log(chalk.green(\"Published widget package version.\"));\n }\n\n printWidgetPublishSummary({\n title: dryRun ? \"Portal deploy dry run\" : \"Portal deploy\",\n ownerLabel: \"company\",\n environment,\n outDir,\n result,\n });\n } catch (err) {\n spinner.fail(\"Portal deploy failed\");\n console.error(\n chalk.red(\"Error:\") +\n \" \" +\n (err instanceof Error ? err.message : String(err)),\n );\n process.exit(1);\n }\n });\n\nexport function registerDeployCommand(ctx: PluginContext): void {\n ctx.program.addCommand(deployCommand);\n}\n","import { Command } from \"commander\";\nimport type { PluginContext } from \"@fluid-app/fluid-cli\";\nimport chalk from \"chalk\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * Severity levels for drift diagnostics.\n * - ERROR: Security-critical or breaking drift (e.g., missing CSP)\n * - WARN: Stale config that may cause subtle issues\n * - INFO: Cosmetic or non-functional differences\n */\nexport type Severity = \"error\" | \"warn\" | \"info\";\n\nexport interface Diagnostic {\n file: string;\n severity: Severity;\n message: string;\n}\n\n/** Files that are managed by the SDK and should match the canonical template. */\nconst INFRASTRUCTURE_FILES = [\n \"index.html\",\n \"tsconfig.json\",\n \"vite.config.ts\",\n \".oxlintrc.json\",\n] as const;\n\n/** Entry files with expected content patterns after Phase 2 absorption. */\nconst ENTRY_CHECKS = [\n {\n file: \"src/main.tsx\",\n expectedPattern: \"createPortal\",\n hint: 'main.tsx should use createPortal() from @fluid-app/portal-sdk. Run \"fluid create\" to see the latest template.',\n },\n {\n file: \"src/index.css\",\n expectedPattern: \"@fluid-app/portal-sdk/globals.css\",\n hint: \"index.css should import @fluid-app/portal-sdk/globals.css instead of inline theme tokens.\",\n },\n] as const;\n\n/** Files that should NOT exist after Phase 2 (absorbed into SDK). */\nconst REMOVED_FILES = [\n {\n file: \"src/App.tsx\",\n hint: \"App.tsx is no longer needed — createPortal() handles the AppShell wiring internally.\",\n },\n {\n file: \"src/fluid.config.ts\",\n hint: \"fluid.config.ts is no longer needed — pass config overrides to createPortal() directly.\",\n },\n] as const;\n\nfunction readFileOrNull(filePath: string): string | null {\n try {\n return readFileSync(filePath, \"utf-8\");\n } catch {\n return null;\n }\n}\n\nconst _currentFile = fileURLToPath(import.meta.url);\nconst _currentDir = dirname(_currentFile);\n\nfunction findTemplateDir(): string | null {\n // Walk up from current file to find package root (works in both dist/ and src/)\n let dir = _currentDir;\n while (!existsSync(join(dir, \"package.json\"))) {\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n const templateDir = join(dir, \"templates\");\n if (existsSync(join(templateDir, \"base\"))) return templateDir;\n return null;\n}\n\nexport function checkInfrastructureDrift(\n cwd: string,\n templateDir: string,\n): Diagnostic[] {\n const diagnostics: Diagnostic[] = [];\n\n for (const file of INFRASTRUCTURE_FILES) {\n const portalPath = join(cwd, file);\n const templatePath = join(templateDir, \"base\", file);\n\n if (!existsSync(portalPath)) {\n diagnostics.push({\n file,\n severity: \"warn\",\n message: `Missing file: ${file}`,\n });\n continue;\n }\n\n if (!existsSync(templatePath)) {\n // Template doesn't have this file — skip\n continue;\n }\n\n const portalContent = readFileOrNull(portalPath);\n const templateContent = readFileOrNull(templatePath);\n\n if (portalContent !== null && templateContent !== null) {\n if (portalContent.trim() !== templateContent.trim()) {\n diagnostics.push({\n file,\n severity: \"warn\",\n message: `Content differs from canonical template. Review and update if needed.`,\n });\n }\n }\n }\n\n return diagnostics;\n}\n\nexport function checkEntryPatterns(cwd: string): Diagnostic[] {\n const diagnostics: Diagnostic[] = [];\n\n for (const check of ENTRY_CHECKS) {\n const filePath = join(cwd, check.file);\n const content = readFileOrNull(filePath);\n\n if (content === null) {\n diagnostics.push({\n file: check.file,\n severity: \"error\",\n message: `Missing file. ${check.hint}`,\n });\n continue;\n }\n\n if (!content.includes(check.expectedPattern)) {\n diagnostics.push({\n file: check.file,\n severity: \"warn\",\n message: `Does not contain expected pattern \"${check.expectedPattern}\". ${check.hint}`,\n });\n }\n }\n\n return diagnostics;\n}\n\nexport function checkRemovedFiles(cwd: string): Diagnostic[] {\n const diagnostics: Diagnostic[] = [];\n\n for (const check of REMOVED_FILES) {\n if (existsSync(join(cwd, check.file))) {\n diagnostics.push({\n file: check.file,\n severity: \"info\",\n message: `File can be removed. ${check.hint}`,\n });\n }\n }\n\n return diagnostics;\n}\n\nfunction formatDiagnostic(d: Diagnostic): string {\n const icon =\n d.severity === \"error\"\n ? chalk.red(\"ERROR\")\n : d.severity === \"warn\"\n ? chalk.yellow(\" WARN\")\n : chalk.blue(\" INFO\");\n\n return ` ${icon} ${chalk.bold(d.file)}\\n ${chalk.dim(d.message)}`;\n}\n\nexport const doctorCommand: Command = new Command(\"doctor\")\n .description(\n \"Check portal for scaffold drift and report stale infrastructure files\",\n )\n .action(async () => {\n const cwd = process.cwd();\n\n // Validate we're in a portal project\n const packageJsonPath = join(cwd, \"package.json\");\n if (!existsSync(packageJsonPath)) {\n console.error(\n chalk.red(\"Error: No package.json found in current directory\"),\n );\n console.error(\n chalk.yellow(\"Make sure you're in a Fluid portal project directory\"),\n );\n process.exit(1);\n }\n\n let packageJson: {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n try {\n packageJson = JSON.parse(readFileSync(packageJsonPath, \"utf-8\"));\n } catch {\n console.error(chalk.red(\"Error: Could not parse package.json\"));\n console.error(chalk.yellow(\"Ensure package.json contains valid JSON\"));\n process.exit(1);\n }\n const deps = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n if (!deps[\"@fluid-app/portal-sdk\"]) {\n console.error(\n chalk.red(\"Error: @fluid-app/portal-sdk not found in dependencies\"),\n );\n console.error(\n chalk.yellow(\n \"This command must be run from a Fluid portal project directory\",\n ),\n );\n process.exit(1);\n }\n\n console.log();\n console.log(chalk.bold(\"Fluid Portal Doctor\"));\n console.log(chalk.dim(\"Checking for scaffold drift...\\n\"));\n\n const diagnostics: Diagnostic[] = [];\n\n // Check entry file patterns\n diagnostics.push(...checkEntryPatterns(cwd));\n\n // Check for files that should be removed\n diagnostics.push(...checkRemovedFiles(cwd));\n\n // Check infrastructure drift against templates (if available)\n const templateDir = findTemplateDir();\n if (templateDir) {\n diagnostics.push(...checkInfrastructureDrift(cwd, templateDir));\n } else {\n console.log(\n chalk.dim(\n \" (Skipping infrastructure diff — template files not available)\\n\",\n ),\n );\n }\n\n // Report results\n if (diagnostics.length === 0) {\n console.log(chalk.green(\" All clear — no drift detected.\\n\"));\n return;\n }\n\n const errors = diagnostics.filter((d) => d.severity === \"error\");\n const warns = diagnostics.filter((d) => d.severity === \"warn\");\n const infos = diagnostics.filter((d) => d.severity === \"info\");\n\n for (const d of [...errors, ...warns, ...infos]) {\n console.log(formatDiagnostic(d));\n console.log();\n }\n\n // Summary\n const parts: string[] = [];\n if (errors.length > 0) parts.push(chalk.red(`${errors.length} error(s)`));\n if (warns.length > 0)\n parts.push(chalk.yellow(`${warns.length} warning(s)`));\n if (infos.length > 0) parts.push(chalk.blue(`${infos.length} info`));\n console.log(` ${parts.join(\", \")}\\n`);\n\n if (errors.length > 0) {\n process.exit(1);\n }\n });\n\nexport function registerDoctorCommand(ctx: PluginContext): void {\n ctx.program.addCommand(doctorCommand);\n}\n","import { Command } from \"commander\";\nimport type { PluginContext } from \"@fluid-app/fluid-cli\";\nimport { getAuthToken } from \"@fluid-app/fluid-cli\";\nimport chalk from \"chalk\";\nimport { createFetchClient, fluidOs } from \"@fluid-app/fluidos-api-client\";\nimport prompts from \"prompts\";\nimport path from \"node:path\";\nimport { readMappings } from \"../utils/mappings.js\";\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst PORTAL_SYNC_DIR = \".portal-sync\";\n\nfunction getApiBase(): string {\n return process.env[\"FLUID_API_BASE\"] ?? \"https://api.fluid.app\";\n}\n\nfunction requireToken(): string {\n const token = getAuthToken();\n if (!token) {\n console.error(\n chalk.red(\"Error:\") +\n \" Not logged in. Run \" +\n chalk.cyan(\"`fluid login`\") +\n \" first.\",\n );\n process.exit(1);\n }\n return token;\n}\n\nfunction createClient(token: string) {\n return createFetchClient({\n baseUrl: getApiBase(),\n getAuthToken: () => token,\n });\n}\n\nasync function requireDefinitionId(): Promise<number> {\n const cwd = process.cwd();\n const mappings = await readMappings(path.join(cwd, PORTAL_SYNC_DIR));\n if (!mappings) {\n console.error(\n chalk.red(\"Error:\") +\n \" No definition pulled. Run \" +\n chalk.cyan(\"`fluid portal pull`\") +\n \" first.\",\n );\n process.exit(1);\n }\n return mappings.definition.id;\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Subcommands\n// ─────────────────────────────────────────────────────────────────────────────\n\nconst createVersionCommand = new Command(\"create\")\n .description(\"Create a new version (snapshot) of the portal definition\")\n .option(\"--activate\", \"Activate the version immediately after creation\")\n .action(async (options: { activate?: boolean }) => {\n const token = requireToken();\n const client = createClient(token);\n const definitionId = await requireDefinitionId();\n\n console.log();\n console.log(chalk.bold(\"Creating version...\"));\n\n let result;\n try {\n result = await fluidOs.fluid_os_v0_create_fluid_osversion(\n client,\n definitionId,\n );\n } catch (err) {\n console.error(\n chalk.red(\"Error:\") +\n \" Failed to create version — \" +\n (err instanceof Error ? err.message : String(err)),\n );\n process.exit(1);\n }\n\n const version = result.version;\n\n if (!version?.id) {\n console.error(\n chalk.red(\"Error:\") +\n \" Failed to create version — unexpected response.\",\n );\n process.exit(1);\n }\n\n console.log();\n console.log(chalk.green(\"Version created successfully.\"));\n console.log();\n console.log(chalk.gray(\"Version ID: \") + chalk.white(version.id));\n\n let active = version.active ?? false;\n\n if (options.activate) {\n console.log(\"Activating version...\");\n try {\n await fluidOs.fluid_os_v0_update_fluid_osversion(\n client,\n definitionId,\n version.id,\n {\n version: { active: true },\n },\n );\n } catch (err) {\n console.error(\n chalk.red(\"Error:\") +\n \" Failed to activate version — \" +\n (err instanceof Error ? err.message : String(err)),\n );\n process.exit(1);\n }\n active = true;\n }\n\n console.log(\n chalk.gray(\"Active: \") +\n (active ? chalk.green(\"yes\") : chalk.gray(\"no\")),\n );\n console.log();\n });\n\nconst listVersionCommand = new Command(\"list\")\n .description(\"List all versions of the portal definition\")\n .action(async () => {\n const token = requireToken();\n const client = createClient(token);\n const definitionId = await requireDefinitionId();\n\n let result;\n try {\n result = await fluidOs.fluid_os_v0_list_fluid_osversions(\n client,\n definitionId,\n );\n } catch (err) {\n console.error(\n chalk.red(\"Error:\") +\n \" Failed to list versions — \" +\n (err instanceof Error ? err.message : String(err)),\n );\n process.exit(1);\n }\n\n const versions = result.version;\n\n if (!Array.isArray(versions) || versions.length === 0) {\n console.log();\n console.log(chalk.yellow(\"No versions found.\"));\n console.log(\n \"Run \" +\n chalk.cyan(\"`fluid portal version create`\") +\n \" to publish a version.\",\n );\n console.log();\n return;\n }\n\n console.log();\n\n // Print table header\n const COL_ID = \"Version ID\".padEnd(36);\n const COL_ACT = \"Active\".padEnd(6);\n const COL_PUB = \"Published\";\n console.log(chalk.gray(` ${COL_ID} ${COL_ACT} ${COL_PUB}`));\n\n for (const v of versions) {\n const id = String(v.id).padEnd(36);\n const active = v.active ? chalk.green(\"\\u2713\") + \" \" : \" \";\n const published = v.published_at\n ? new Date(v.published_at).toLocaleString()\n : \"\\u2014\";\n console.log(` ${id} ${active} ${published}`);\n }\n\n console.log();\n });\n\nconst activateVersionCommand = new Command(\"activate\")\n .description(\"Activate a specific version, making it the live version\")\n .argument(\"<version-id>\", \"The version ID to activate\")\n .option(\"-y, --yes\", \"Skip confirmation prompt\")\n .action(async (versionId: string, options: { yes?: boolean }) => {\n const token = requireToken();\n const client = createClient(token);\n const definitionId = await requireDefinitionId();\n\n if (!options.yes) {\n const { confirm } = await prompts({\n type: \"confirm\",\n name: \"confirm\",\n message: `Activate version ${versionId}? This will make it the live version.`,\n initial: false,\n });\n\n if (!confirm) {\n console.log(chalk.yellow(\"Aborted.\"));\n return;\n }\n }\n\n console.log();\n console.log(chalk.bold(\"Activating version...\"));\n\n try {\n await fluidOs.fluid_os_v0_update_fluid_osversion(\n client,\n definitionId,\n versionId,\n {\n version: { active: true },\n },\n );\n } catch (err) {\n console.error(\n chalk.red(\"Error:\") +\n \" Failed to activate version — \" +\n (err instanceof Error ? err.message : String(err)),\n );\n process.exit(1);\n }\n\n console.log();\n console.log(chalk.green(\"Version \" + versionId + \" is now active.\"));\n console.log();\n });\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Version command group\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport const versionCommand: Command = new Command(\"version\")\n .description(\"Manage portal definition versions\")\n .addCommand(createVersionCommand)\n .addCommand(listVersionCommand)\n .addCommand(activateVersionCommand);\n\nexport function registerVersionCommand(ctx: PluginContext): void {\n ctx.program.addCommand(versionCommand);\n}\n","import { Command } from \"commander\";\nimport type { PluginContext } from \"@fluid-app/fluid-cli\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport type { WidgetPublishOptions } from \"../types.js\";\nimport {\n createAuthenticatedWidgetPackageClient,\n printDryRunSessionPayload,\n printWidgetPublishSummary,\n printRuntimeOnlyNotice,\n publishWidgetRuntimeArtifacts,\n} from \"./widget-package-publish.js\";\n\nconst DEFAULT_OUT_DIR = \".fluid/widget-dist\";\n\nconst publishSubcommand = new Command(\"publish\")\n .description(\"Publish droplet-owned widget runtime artifacts\")\n .requiredOption(\n \"--droplet <uuid>\",\n \"Droplet UUID that owns the widget package\",\n )\n .option(\n \"-o, --out-dir <dir>\",\n \"Widget artifact output directory\",\n DEFAULT_OUT_DIR,\n )\n .option(\"--dry-run\", \"Build and validate upload payload without publishing\")\n .action(async (options: WidgetPublishOptions) => {\n const outDir = options.outDir ?? DEFAULT_OUT_DIR;\n const dryRun = options.dryRun === true;\n\n console.log();\n console.log(chalk.blue.bold(\"Fluid Widget Publish\"));\n console.log();\n printRuntimeOnlyNotice();\n console.log(chalk.gray(\"Droplet: \") + chalk.white(options.droplet));\n console.log(chalk.gray(\"Output: \") + chalk.cyan(outDir));\n if (dryRun)\n console.log(chalk.yellow(\"Dry run: no upload will be created.\"));\n console.log();\n\n const spinner = ora(\"Building droplet-owned widget package...\").start();\n\n try {\n const result = await publishWidgetRuntimeArtifacts({\n projectDir: process.cwd(),\n outDir,\n buildOwner: \"droplet\",\n uploadOwner: { kind: \"droplet\", uuid: options.droplet },\n dryRun,\n ...(dryRun ? {} : { client: createAuthenticatedWidgetPackageClient() }),\n });\n\n spinner.succeed(\"Built widget runtime artifacts\");\n\n if (dryRun) {\n console.log(\n chalk.yellow(\"Dry run complete — upload session was not requested.\"),\n );\n console.log();\n printDryRunSessionPayload(result);\n } else {\n console.log(chalk.green(\"Published widget package version.\"));\n }\n\n printWidgetPublishSummary({\n title: dryRun ? \"Widget publish dry run\" : \"Widget publish\",\n ownerLabel: `droplet ${options.droplet}`,\n outDir,\n result,\n });\n } catch (err) {\n spinner.fail(\"Widget publish failed\");\n console.error(\n chalk.red(\"Error:\") +\n \" \" +\n (err instanceof Error ? err.message : String(err)),\n );\n process.exit(1);\n }\n });\n\nexport const topLevelWidgetCommand: Command = new Command(\"widget\")\n .description(\"Publish Fluid widget packages\")\n .addCommand(publishSubcommand);\n\nexport function registerTopLevelWidgetCommand(ctx: PluginContext): void {\n ctx.program.addCommand(topLevelWidgetCommand);\n}\n","/**\n * @fluid-app/fluid-cli-portal\n *\n * Fluid CLI plugin for building portal applications.\n * Auto-discovered by @fluid-app/fluid-cli via the fluid-cli-* naming convention.\n */\n\nimport { Command } from \"commander\";\nimport type { FluidPlugin, PluginContext } from \"@fluid-app/fluid-cli\";\nimport { createCommand } from \"./commands/create.js\";\nimport { devCommand } from \"./commands/dev.js\";\nimport { buildCommand } from \"./commands/build.js\";\nimport { pullCommand } from \"./commands/pull.js\";\nimport { pushCommand } from \"./commands/push.js\";\nimport { widgetCommand } from \"./commands/widget-create.js\";\nimport { deployCommand } from \"./commands/deploy.js\";\nimport { doctorCommand } from \"./commands/doctor.js\";\nimport { versionCommand } from \"./commands/version.js\";\n\nconst plugin: FluidPlugin = {\n name: \"fluid-cli-portal\",\n version: \"0.1.0\",\n async register(ctx: PluginContext) {\n const portal = new Command(\"portal\").description(\n \"Build and develop portal applications\",\n );\n\n portal.addCommand(createCommand);\n portal.addCommand(devCommand);\n portal.addCommand(buildCommand);\n portal.addCommand(pullCommand);\n portal.addCommand(pushCommand);\n portal.addCommand(deployCommand);\n portal.addCommand(widgetCommand);\n portal.addCommand(doctorCommand);\n portal.addCommand(versionCommand);\n\n ctx.program.addCommand(portal);\n },\n};\n\nexport default plugin;\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Re-exports for programmatic usage (e.g., @fluid-app/create-portal-app)\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport type {\n ProjectConfig,\n CreateOptions,\n DevOptions,\n BuildOptions,\n TemplateVariables,\n SelectedPageTemplate,\n TemplateName,\n WidgetCreateOptions,\n PortalDeployOptions,\n WidgetPublishOptions,\n} from \"./types.js\";\n\nexport { TEMPLATES } from \"./types.js\";\n\nexport {\n getInstallCommand,\n getRunCommand,\n runPackageManager,\n installDependencies,\n} from \"./utils/package-manager.js\";\n\nexport {\n getTemplatePaths,\n copyTemplate,\n directoryExists,\n fileExists,\n pathExists,\n createDirectory,\n getSdkVersion,\n readFileSafe,\n writeFileSafe,\n createDirectorySafe,\n copyTemplateSafe,\n getSdkVersionSafe,\n FILE_SYSTEM_ERRORS,\n type FileSystemErrorCode,\n type FileSystemError,\n type TemplatePaths,\n} from \"./utils/file-system.js\";\n\nexport { promptProjectConfig } from \"./utils/prompts.js\";\n\n// Expose the standalone Command for create-portal-app\nexport { createCommand } from \"./commands/create.js\";\nexport { pullCommand } from \"./commands/pull.js\";\nexport { pushCommand } from \"./commands/push.js\";\nexport { widgetCommand } from \"./commands/widget-create.js\";\nexport { topLevelWidgetCommand } from \"./commands/widget-publish.js\";\nexport { deployCommand } from \"./commands/deploy.js\";\nexport { versionCommand } from \"./commands/version.js\";\nexport { doctorCommand } from \"./commands/doctor.js\";\n\nexport {\n readMappings,\n writeMappings,\n deriveSlug,\n resolveSlugToId,\n resolveIdToSlug,\n updateMapping,\n removeMapping,\n type PortalMappings,\n type DefinitionMapping,\n type MappedResourceType,\n} from \"./utils/mappings.js\";\n\nexport {\n computeFileHash,\n readSnapshot,\n writeSnapshot,\n diffAgainstSnapshot,\n buildSnapshot,\n type Snapshot,\n type SnapshotDiff,\n type FileHash,\n type FileHashMap,\n} from \"./utils/snapshot.js\";\n\nexport {\n transformScreen,\n deriveScreenSlug,\n transformTheme,\n transformNavigation,\n transformNavigationItems,\n transformProfile,\n buildIdToSlugMap,\n buildNavigationIdToSlugMap,\n buildThemeIdToSlugMap,\n type LocalScreen,\n type LocalTheme,\n type LocalNavigation,\n type LocalNavigationItem,\n type LocalProfile,\n} from \"./utils/transform.js\";\n\nexport {\n categorizeChanges,\n validateCrossReferences,\n slugFromPath,\n type CategorizedChanges,\n type ValidationError,\n} from \"./utils/push-validation.js\";\n\nexport {\n buildSharedWidgetPackage,\n createWidgetPackageEntrySource,\n type BuildSharedWidgetPackageOptions,\n type SharedWidgetPackageBuildResult,\n type SharedWidgetPackageBuildError,\n} from \"./utils/widget-package-builder.js\";\n\nexport {\n resolvePortalWidgetSourceConfig,\n loadSourceWidgetPackages,\n type WidgetSourceConfig,\n type WidgetSourceConfigLoadError,\n} from \"./utils/widget-package-config.js\";\n\nexport {\n validateSingleSourceWidgetPackage,\n buildWidgetPackageDescriptor,\n type SourceWidgetMetadata,\n type SourceWidgetPackageMetadata,\n type WidgetDescriptorMetadata,\n type WidgetPackageDescriptorMetadata,\n type ValidatedWidgetPackageBuild,\n type WidgetPackageValidationErrorCode,\n type WidgetPackageValidationError,\n type WidgetPackageValidationResult,\n type ValidateSourceWidgetPackageOptions,\n type WidgetPackageOwnerKind,\n} from \"./utils/widget-package-validation.js\";\n\nexport {\n WIDGET_PACKAGE_BUILDER_VERSION,\n computeArtifactMetadata,\n collectWidgetPackageArtifacts,\n createPublishManifestMetadata,\n getArtifactContentType,\n sha256,\n type ArtifactMetadata,\n type PublishManifestMetadata,\n} from \"./utils/widget-package-artifacts.js\";\n\nexport {\n publishWidgetRuntimeArtifacts,\n createWidgetPackagePublishRequest,\n createAuthenticatedWidgetPackageClient,\n printDryRunSessionPayload,\n printWidgetPublishSummary,\n printRuntimeOnlyNotice,\n validateWidgetPublishOutDir,\n type PublishWidgetRuntimeArtifactsOptions,\n type PublishWidgetRuntimeArtifactsResult,\n type PublishWidgetRuntimeArtifactsDependencies,\n} from \"./commands/widget-package-publish.js\";\n\nexport {\n buildWidgetPackageUploadSessionPayload,\n getWidgetPackageUploadSessionRoute,\n getWidgetPackageCompleteUploadRoute,\n requestWidgetPackageUploadSession,\n uploadWidgetPackageArtifacts,\n completeWidgetPackageUpload,\n publishWidgetPackageVersion,\n normalizeWidgetPackageUploadSession,\n normalizeWidgetPackageCompleteResponse,\n buildWidgetPackageCompleteUploadPayload,\n WidgetPackageUploadError,\n type WidgetPackageUploadOwner,\n type WidgetPackageArtifactMetadata,\n type WidgetPackageUploadArtifact,\n type WidgetPackageSessionRequest,\n type WidgetPackagePublishRequest,\n type WidgetPackageArtifactPayload,\n type WidgetPackageUploadSessionPayload,\n type WidgetPackageCompleteUploadPayload,\n type WidgetPackageSignedUpload,\n type WidgetPackageUploadSession,\n type WidgetPackageArtifactUploadResult,\n type WidgetPackageCompleteResult,\n type WidgetPackagePublishResult,\n type PublishWidgetPackageVersionOptions,\n type WidgetPackageUploadFetch,\n} from \"./utils/widget-package-upload.js\";\n"],"mappings":"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"}
|